Merge remote-tracking branch 'upstream/devel'

This commit is contained in:
wowario 2019-11-07 11:09:42 +03:00
commit ccd4bc2fcc
35 changed files with 950 additions and 6532 deletions

View file

@ -28,6 +28,18 @@ if (NOT MONERO_BUILD_DIR)
# set location of monero build tree
set(MONERO_BUILD_DIR ${MONERO_SOURCE_DIR}/build/release/
CACHE PATH "Path to the build directory for Monero")
if (NOT EXISTS ${MONERO_BUILD_DIR})
# try different location
message(STATUS "Trying different folder for monero libraries")
set(MONERO_BUILD_DIR ${MONERO_SOURCE_DIR}/build/Linux/master/release/
CACHE PATH "Path to the build directory for Monero" FORCE)
endif()
endif()
if (NOT EXISTS ${MONERO_BUILD_DIR})
message(FATAL_ERROR "Monero libraries not found in: ${MONERO_BUILD_DIR}")
endif()
set(MY_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake"
@ -128,6 +140,7 @@ set(LIBRARIES
checkpoints
version
epee
hardforks
randomx
sodium
${Boost_LIBRARIES}

View file

@ -34,6 +34,7 @@ Clearnet versions:
- [http://monerochain.com/](http://monerochain.com/) - JSON API based, multiple nodes.
- [https://blox.minexmr.com/](https://blox.minexmr.com/) - - https enabled.
- [https://community.xmr.to/explorer/mainnet/](https://community.xmr.to/explorer/mainnet/)
- [https://exp.xmr.sk/](https://exp.xmr.sk/)
Testnet version:
@ -64,7 +65,6 @@ Alternative block explorers:
The key features of the Onion Monero Blockchain Explorer are:
- no cookies, no web analytics trackers, no images,
- by default no JavaScript, but can be enabled for client side decoding and proving transactions,
- open sourced,
- made fully in C++,
- showing encrypted payments ID,
@ -81,6 +81,7 @@ The key features of the Onion Monero Blockchain Explorer are:
- can provide total amount of all miner fees,
- decoding encrypted payment id,
- decoding outputs and proving txs sent to sub-address.
- listing RandomX code for each block
## Development branch
@ -93,18 +94,11 @@ Note: `devel` branch of the explorer follows `master` branch of the monero.
## Compilation on Ubuntu 16.04/18.04
##### Compile latest Monero version (0.14.0.2)
Download and compile recent Monero into your home folder:
#### Monero download and compilation
```bash
# first install monero dependecines
sudo apt update
sudo apt install git build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libcurl4-openssl-dev libgtest-dev libreadline-dev libzmq3-dev libsodium-dev libhidapi-dev libhidapi-libusb0
# go to home folder
cd ~
To download and compile recent Monero follow instructions
in the following link:
# download monero sourced for master branch
git clone --recursive https://github.com/monero-project/monero.git
@ -116,7 +110,7 @@ USE_SINGLE_BUILDDIR=1 make
##### Compile and run the explorer
Once the Monero is compiles, the explorer can be downloaded and compiled
Once the Monero compiles, the explorer can be downloaded and compiled
as follows:
```bash
@ -135,12 +129,6 @@ mkdir build && cd build
# create the makefile
cmake ..
# altearnatively can use: cmake -DMONERO_DIR=/path/to/monero_folder ..
# if monero is not in ~/monero
#
# also can build with ASAN (sanitizers), for example
# cmake -DSANITIZE_ADDRESS=On ..
# compile
make
```
@ -178,6 +166,7 @@ xmrblocks, Onion Monero Blockchain Explorer:
-t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain
-s [ --stagenet ] [=arg(=1)] (=0) use stagenet blockchain
--enable-pusher [=arg(=1)] (=0) enable signed transaction pusher
--enable-randomx [=arg(=1)] (=0) enable generation of randomx code
--enable-mixin-details [=arg(=1)] (=0)
enable mixin details for key images,
e.g., timescale, mixin of mixins, in tx
@ -186,13 +175,9 @@ xmrblocks, Onion Monero Blockchain Explorer:
enable key images file checker
--enable-output-key-checker [=arg(=1)] (=0)
enable outputs key file checker
--enable-json-api [=arg(=1)] (=1) enable JSON REST api
--enable-tx-cache [=arg(=1)] (=0) enable caching of transaction details
--show-cache-times [=arg(=1)] (=0) show times of getting data from cache
vs no cache
--enable-block-cache [=arg(=1)] (=0) enable caching of block details
--enable-js [=arg(=1)] (=0) enable checking outputs and proving txs
using JavaScript on client side
--enable-json-api [=arg(=1)] (=0) enable JSON REST api
--enable-as-hex [=arg(=1)] (=0) enable links to provide hex
represtations of a tx and a block
--enable-autorefresh-option [=arg(=1)] (=0)
enable users to have the index page on
autorefresh
@ -200,6 +185,7 @@ xmrblocks, Onion Monero Blockchain Explorer:
enable Monero total emission monitoring
thread
-p [ --port ] arg (=8081) default explorer port
-x [ --bindaddr ] arg (=0.0.0.0) default bind address for the explorer
--testnet-url arg you can specify testnet url, if you run
it on mainnet or stagenet. link will
show on front page to testnet explorer
@ -215,6 +201,9 @@ xmrblocks, Onion Monero Blockchain Explorer:
for mempool data for the front page
--mempool-refresh-time arg (=5) time, in seconds, for each refresh of
mempool state
-c [ --concurrency ] arg (=0) number of threads handling http
queries. Default is 0 which means it is
based you on the cpu
-b [ --bc-path ] arg path to lmdb folder of the blockchain,
e.g., ~/.bitmonero/lmdb
--ssl-crt-file arg path to crt file for ssl (https)
@ -222,7 +211,7 @@ xmrblocks, Onion Monero Blockchain Explorer:
--ssl-key-file arg path to key file for ssl (https)
functionality
-d [ --deamon-url ] arg (=http:://127.0.0.1:18081)
Monero deamon url
Monero daemon url
```
Example usage, defined as bash aliases.
@ -235,8 +224,6 @@ alias xmrblocksmainnet='~/onion-monero-blockchain-explorer/build/xmrblocks --
alias xmrblockstestnet='~/onion-monero-blockchain-explorer/build/xmrblocks -t --port 8082 --mainnet-url "http://139.162.32.245:8081" --enable-pusher --enable-emission-monitor'
```
These are aliases similar to those used for http://139.162.32.245:8081/ and http://139.162.32.245:8082/, respectively.
## Enable Monero emission
Obtaining current Monero emission amount is not straight forward. Thus, by default it is
@ -276,15 +263,6 @@ For example, for the above example: `print_coinbase_tx_sum 0 1313449`.
To disable the monitor, simply restart the explorer without `--enable-emission-monitor` flag.
## Enable JavaScript for decoding proving transactions
By default, decoding and proving tx's outputs are done on the server side. To do this on the client side
(private view and tx keys are not send to the server) JavaScript-based decoding can be enabled:
```
xmrblocks --enable-js
```
## Enable SSL (https)
By default, the explorer does not use ssl. But it has such a functionality.

View file

@ -31,7 +31,7 @@
set(LIBS common;blocks;cryptonote_basic;cryptonote_core;multisig;
cryptonote_protocol;daemonizer;mnemonics;epee;lmdb;device;
blockchain_db;ringct;wallet;cncrypto;easylogging;version;
checkpoints;randomx)
checkpoints;randomx;hardforks)
set(Xmr_INCLUDE_DIRS "${CPP_MONERO_DIR}")
@ -71,7 +71,9 @@ message(STATUS ${MONERO_SOURCE_DIR}/build)
# include monero headers
include_directories(
${MONERO_SOURCE_DIR}/src
${MONERO_SOURCE_DIR}/src/crypto
${MONERO_SOURCE_DIR}/external
${MONERO_SOURCE_DIR}/external/randomx/src
${MONERO_SOURCE_DIR}/build
${MONERO_SOURCE_DIR}/external/easylogging++
${MONERO_SOURCE_DIR}/contrib/epee/include

View file

@ -4,6 +4,11 @@
#include <boost/asio/ssl.hpp>
#endif
#include "crow/settings.h"
#if BOOST_VERSION >= 107000
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
#else
#define GET_IO_SERVICE(s) ((s).get_io_service())
#endif
namespace crow
{
using namespace boost;
@ -19,7 +24,7 @@ namespace crow
boost::asio::io_service& get_io_service()
{
return socket_.get_io_service();
return GET_IO_SERVICE(socket_);
}
tcp::socket& raw_socket()
@ -94,7 +99,7 @@ namespace crow
boost::asio::io_service& get_io_service()
{
return raw_socket().get_io_service();
return GET_IO_SERVICE(raw_socket());
}
template <typename F>

View file

@ -1,138 +0,0 @@
#ifndef CACHE_HPP
#define CACHE_HPP
#include <cstddef>
#include <limits>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "cache_policy.hpp"
namespace caches
{
// Base class for caching algorithms
template <typename Key, typename Value, typename Policy = NoCachePolicy<Key>>
class fixed_sized_cache
{
public:
using iterator = typename std::unordered_map<Key, Value>::iterator;
using const_iterator =
typename std::unordered_map<Key, Value>::const_iterator;
using operation_guard = typename std::lock_guard<std::mutex>;
fixed_sized_cache(
size_t max_size,
const Policy& policy = Policy())
: max_cache_size{max_size},
cache_policy(policy)
{
if (max_cache_size == 0)
{
max_cache_size = std::numeric_limits<size_t>::max();
}
}
void Put(const Key& key, const Value& value)
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
if (elem_it == cache_items_map.end())
{
// add new element to the cache
if (Size() + 1 > max_cache_size)
{
auto disp_candidate_key = cache_policy.ReplCandidate();
Erase(disp_candidate_key);
}
Insert(key, value);
}
else
{
// update previous value
Update(key, value);
}
}
bool Contains(const Key& key)
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
return elem_it != cache_items_map.end();
}
const Value& Get(const Key& key) const
{
operation_guard{safe_op};
auto elem_it = FindElem(key);
if (elem_it == cache_items_map.end())
{
throw std::range_error{"No such element in the cache"};
}
cache_policy.Touch(key);
return elem_it->second;
}
const size_t Size() const
{
operation_guard{safe_op};
return cache_items_map.size();
}
// return a key of a displacement candidate
void Clear()
{
operation_guard{safe_op};
cache_policy.Clear();
cache_items_map.clear();
}
protected:
void Insert(const Key& key, const Value& value)
{
cache_policy.Insert(key);
cache_items_map.emplace(std::make_pair(key, value));
}
void Erase(const Key& key)
{
cache_policy.Erase(key);
cache_items_map.erase(key);
}
void Update(const Key& key, const Value& value)
{
cache_policy.Touch(key);
cache_items_map[key] = value;
}
const_iterator FindElem(const Key& key) const
{
return cache_items_map.find(key);
}
private:
std::unordered_map<Key, Value> cache_items_map;
mutable Policy cache_policy;
mutable std::mutex safe_op;
size_t max_cache_size;
};
}
#endif // CACHE_HPP

View file

@ -1,77 +0,0 @@
#ifndef CACHE_POLICY_HPP
#define CACHE_POLICY_HPP
#include <unordered_set>
namespace caches
{
template <typename Key>
class ICachePolicy
{
public:
virtual ~ICachePolicy() {}
// handle element insertion in a cache
virtual void Insert(const Key& key) = 0;
// handle request to the key-element in a cache
virtual void Touch(const Key& key) = 0;
// handle element deletion from a cache
virtual void Erase(const Key& key) = 0;
// return a key of a replacement candidate
virtual const Key& ReplCandidate() const = 0;
// clear the cache
virtual void Clear() = 0;
};
template <typename Key>
class NoCachePolicy : public ICachePolicy<Key>
{
public:
NoCachePolicy() = default;
~NoCachePolicy() override = default;
void Insert(const Key& key) override
{
key_storage.emplace(key);
}
void Touch(const Key& key) override
{
// do not do anything
}
void Erase(const Key& key) override
{
key_storage.erase(key);
}
// return a key of a displacement candidate
const Key& ReplCandidate() const override
{
return *key_storage.crbegin();
}
// return a key of a displacement candidate
void Clear() override
{
key_storage.clear();
}
private:
std::unordered_set<Key> key_storage;
};
} // namespace caches
#endif // CACHE_POLICY_HPP

View file

@ -1,53 +0,0 @@
#ifndef FIFO_CACHE_POLICY_HPP
#define FIFO_CACHE_POLICY_HPP
#include <list>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class FIFOCachePolicy : public ICachePolicy<Key>
{
public:
FIFOCachePolicy() = default;
~FIFOCachePolicy() = default;
void Insert(const Key& key) override
{
fifo_queue.emplace_front(key);
}
// handle request to the key-element in a cache
void Touch(const Key& key) override
{
// nothing to do here in the FIFO strategy
}
// handle element deletion from a cache
void Erase(const Key& key) override
{
fifo_queue.pop_back();
}
// return a key of a replacement candidate
const Key& ReplCandidate() const override
{
return fifo_queue.back();
}
// return a key of a displacement candidate
void Clear() override
{
fifo_queue.clear();
}
private:
std::list<Key> fifo_queue;
};
} // namespace caches
#endif // FIFO_CACHE_POLICY_HPP

View file

@ -1,76 +0,0 @@
#ifndef LFU_CACHE_POLICY_HPP
#define LFU_CACHE_POLICY_HPP
#include <cstddef>
#include <unordered_map>
#include <map>
#include <iostream>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class LFUCachePolicy : public ICachePolicy<Key>
{
public:
using lfu_iterator = typename std::multimap<std::size_t, Key>::iterator;
LFUCachePolicy() = default;
~LFUCachePolicy() override = default;
void Insert(const Key& key) override
{
constexpr std::size_t INIT_VAL = 1;
// all new value initialized with the frequency 1
lfu_storage[key] = frequency_storage.emplace_hint(
frequency_storage.cbegin(), INIT_VAL, key);
}
void Touch(const Key& key) override
{
// get the previous frequency value of a key
auto elem_for_update = lfu_storage[key];
auto updated_elem = std::make_pair(
elem_for_update->first + 1, elem_for_update->second);
// update the previous value
frequency_storage.erase(elem_for_update);
lfu_storage[key] = frequency_storage.emplace_hint(
frequency_storage.cend(), std::move(updated_elem));
}
void Erase(const Key& key) override
{
frequency_storage.erase(lfu_storage[key]);
lfu_storage.erase(key);
}
const Key& ReplCandidate() const override
{
// at the beginning of the frequency_storage we have the
// least frequency used value
return frequency_storage.cbegin()->second;
}
// return a key of a displacement candidate
void Clear() override
{
frequency_storage.clear();
lfu_storage.clear();
}
private:
std::multimap<std::size_t, Key> frequency_storage;
std::unordered_map<Key, lfu_iterator> lfu_storage;
};
} // namespace caches
#endif // LFU_CACHE_POLICY_HPP

View file

@ -1,63 +0,0 @@
#ifndef LRU_CACHE_POLICY_HPP
#define LRU_CACHE_POLICY_HPP
#include <list>
#include <unordered_map>
#include "cache_policy.hpp"
namespace caches
{
template <typename Key>
class LRUCachePolicy : public ICachePolicy<Key>
{
public:
using lru_iterator = typename std::list<Key>::const_iterator;
LRUCachePolicy() = default;
~LRUCachePolicy() = default;
void Insert(const Key& key) override
{
lru_queue.emplace_front(key);
key_finder[key] = lru_queue.cbegin();
}
void Touch(const Key& key) override
{
// move the touched element at the beginning of the lru_queue
lru_queue.splice(lru_queue.cbegin(), lru_queue, key_finder[key]);
}
void Erase(const Key& key) override
{
// remove the least recently used element
key_finder.erase(lru_queue.back());
lru_queue.pop_back();
}
// return a key of a displacement candidate
const Key& ReplCandidate() const override
{
return lru_queue.back();
}
// return a key of a displacement candidate
void Clear() override
{
lru_queue.clear();
key_finder.clear();
}
private:
std::list<Key> lru_queue;
std::unordered_map<Key, lru_iterator> key_finder;
};
} // namespace caches
#endif // LRU_CACHE_POLICY_HPP

110
main.cpp
View file

@ -41,6 +41,7 @@ struct jsonresponse: public crow::response
int
main(int ac, const char* av[])
{
// get command line options
xmreg::CmdLineOptions opts {ac, av};
@ -70,13 +71,11 @@ main(int ac, const char* av[])
auto enable_output_key_checker_opt = opts.get_option<bool>("enable-output-key-checker");
auto enable_autorefresh_option_opt = opts.get_option<bool>("enable-autorefresh-option");
auto enable_pusher_opt = opts.get_option<bool>("enable-pusher");
auto enable_js_opt = opts.get_option<bool>("enable-js");
auto enable_randomx_opt = opts.get_option<bool>("enable-randomx");
auto enable_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
auto enable_json_api_opt = opts.get_option<bool>("enable-json-api");
auto enable_as_hex_opt = opts.get_option<bool>("enable-as-hex");
auto enable_tx_cache_opt = opts.get_option<bool>("enable-tx-cache");
auto enable_block_cache_opt = opts.get_option<bool>("enable-block-cache");
auto show_cache_times_opt = opts.get_option<bool>("show-cache-times");
auto concurrency_opt = opts.get_option<size_t>("concurrency");
auto enable_emission_monitor_opt = opts.get_option<bool>("enable-emission-monitor");
@ -95,17 +94,14 @@ main(int ac, const char* av[])
cryptonote::network_type::STAGENET : cryptonote::network_type::MAINNET;
bool enable_pusher {*enable_pusher_opt};
bool enable_js {*enable_js_opt};
bool enable_randomx {*enable_randomx_opt};
bool enable_key_image_checker {*enable_key_image_checker_opt};
bool enable_autorefresh_option {*enable_autorefresh_option_opt};
bool enable_output_key_checker {*enable_output_key_checker_opt};
bool enable_mixin_details {*enable_mixin_details_opt};
bool enable_json_api {*enable_json_api_opt};
bool enable_as_hex {*enable_as_hex_opt};
bool enable_tx_cache {*enable_tx_cache_opt};
bool enable_block_cache {*enable_block_cache_opt};
bool enable_emission_monitor {*enable_emission_monitor_opt};
bool show_cache_times {*show_cache_times_opt};
// set monero log output level
@ -275,15 +271,12 @@ main(int ac, const char* av[])
deamon_url,
nettype,
enable_pusher,
enable_js,
enable_randomx,
enable_as_hex,
enable_key_image_checker,
enable_output_key_checker,
enable_autorefresh_option,
enable_mixin_details,
enable_tx_cache,
enable_block_cache,
show_cache_times,
no_blocks_on_index,
mempool_info_timeout,
*testnet_url,
@ -313,6 +306,11 @@ main(int ac, const char* av[])
([&](size_t block_height) {
return myxmr::htmlresponse(xmrblocks.show_block(block_height));
});
CROW_ROUTE(app, "/randomx/<uint>")
([&](size_t block_height) {
return myxmr::htmlresponse(xmrblocks.show_randomx(block_height));
});
CROW_ROUTE(app, "/block/<string>")
([&](string block_hash) {
@ -325,6 +323,16 @@ main(int ac, const char* av[])
return myxmr::htmlresponse(
xmrblocks.show_tx(remove_bad_chars(tx_hash)));
});
if (enable_autorefresh_option)
{
CROW_ROUTE(app, "/tx/<string>/autorefresh")
([&](string tx_hash) {
bool refresh_page {true};
uint16_t with_ring_signatures {0};
return myxmr::htmlresponse(
xmrblocks.show_tx(remove_bad_chars(tx_hash), with_ring_signatures, refresh_page));
});
}
if (enable_as_hex)
{
@ -374,6 +382,15 @@ main(int ac, const char* av[])
xmrblocks.show_tx(remove_bad_chars(tx_hash),
with_ring_signatures));
});
if (enable_autorefresh_option)
{
CROW_ROUTE(app, "/tx/<string>/<uint>/autorefresh")
([&](string tx_hash, uint16_t with_ring_signature) {
bool refresh_page {true};
return myxmr::htmlresponse(
xmrblocks.show_tx(remove_bad_chars(tx_hash), with_ring_signature, refresh_page));
});
}
CROW_ROUTE(app, "/myoutputs").methods("POST"_method)
([&](const crow::request& req) -> myxmr::htmlresponse
@ -602,64 +619,6 @@ main(int ac, const char* av[])
return text;
});
if (enable_js)
{
cout << "Enable JavaScript checking of outputs and proving txs\n";
CROW_ROUTE(app, "/js/jquery.min.js")
([&]() {
return xmrblocks.get_js_file("jquery.min.js");
});
CROW_ROUTE(app, "/js/crc32.js")
([&]() {
return xmrblocks.get_js_file("crc32.js");
});
CROW_ROUTE(app, "/js/biginteger.js")
([&]() {
return xmrblocks.get_js_file("biginteger.js");
});
CROW_ROUTE(app, "/js/crypto.js")
([&]() {
return xmrblocks.get_js_file("crypto.js");
});
CROW_ROUTE(app, "/js/config.js")
([&]() {
return xmrblocks.get_js_file("config.js");
});
CROW_ROUTE(app, "/js/nacl-fast-cn.js")
([&]() {
return xmrblocks.get_js_file("nacl-fast-cn.js");
});
CROW_ROUTE(app, "/js/base58.js")
([&]() {
return xmrblocks.get_js_file("base58.js");
});
CROW_ROUTE(app, "/js/cn_util.js")
([&]() {
return xmrblocks.get_js_file("cn_util.js");
});
CROW_ROUTE(app, "/js/sha3.js")
([&]() {
return xmrblocks.get_js_file("sha3.js");
});
CROW_ROUTE(app, "/js/all_in_one.js")
([&]() {
// /js/all_in_one.js file does not exist. it is generated on the fly
// from the above real files.
return xmrblocks.get_js_file("all_in_one.js");
});
} // if (enable_js)
if (enable_json_api)
{
@ -865,10 +824,17 @@ main(int ac, const char* av[])
else
{
cout << "Staring in non-ssl mode" << endl;
app.bindaddr(bindaddr).port(app_port).multithreaded().run();
if (*concurrency_opt == 0)
{
app.bindaddr(bindaddr).port(app_port).multithreaded().run();
}
else
{
app.bindaddr(bindaddr).port(app_port)
.concurrency(*concurrency_opt).run();
}
}
if (enable_emission_monitor == true)
{
// finish Emission monitoring thread in a cotrolled manner.

View file

@ -14,7 +14,13 @@ set(SOURCE_FILES
CmdLineOptions.cpp
page.h
rpccalls.cpp rpccalls.h
version.h.in CurrentBlockchainStatus.cpp MempoolStatus.cpp MempoolStatus.h)
version.h.in
CurrentBlockchainStatus.cpp
MempoolStatus.cpp
MempoolStatus.h)
add_subdirectory(crypto)
# make static library called libmyxrm
# that we are going to link to
@ -22,3 +28,6 @@ set(SOURCE_FILES
add_library(myxrm
STATIC
${SOURCE_FILES})
target_link_libraries(myxrm mycrypto)

View file

@ -29,6 +29,8 @@ namespace xmreg
"use stagenet blockchain")
("enable-pusher", value<bool>()->default_value(false)->implicit_value(true),
"enable signed transaction pusher")
("enable-randomx", value<bool>()->default_value(false)->implicit_value(true),
"enable generation of randomx code")
("enable-mixin-details", value<bool>()->default_value(false)->implicit_value(true),
"enable mixin details for key images, e.g., timescale, mixin of mixins, in tx context")
("enable-key-image-checker", value<bool>()->default_value(false)->implicit_value(true),
@ -37,14 +39,6 @@ namespace xmreg
"enable outputs key file checker")
("enable-json-api", value<bool>()->default_value(false)->implicit_value(true),
"enable JSON REST api")
("enable-tx-cache", value<bool>()->default_value(false)->implicit_value(true),
"enable caching of transaction details")
("show-cache-times", value<bool>()->default_value(false)->implicit_value(true),
"show times of getting data from cache vs no cache")
("enable-block-cache", value<bool>()->default_value(false)->implicit_value(true),
"enable caching of block details")
("enable-js", value<bool>()->default_value(false)->implicit_value(true),
"enable checking outputs and proving txs using JavaScript on client side")
("enable-as-hex", value<bool>()->default_value(false)->implicit_value(true),
"enable links to provide hex represtations of a tx and a block")
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
@ -67,6 +61,8 @@ namespace xmreg
"maximum time, in milliseconds, to wait for mempool data for the front page")
("mempool-refresh-time", value<string>()->default_value("5"),
"time, in seconds, for each refresh of mempool state")
("concurrency,c", value<size_t>()->default_value(0),
"number of threads handling http queries. Default is 0 which means it is based you on the cpu")
("bc-path,b", value<string>(),
"path to lmdb folder of the blockchain, e.g., ~/.wownero/lmdb")
("ssl-crt-file", value<string>(),

View file

@ -275,8 +275,11 @@ MempoolStatus::read_network_info()
local_copy.height = rpc_network_info.height;
local_copy.target_height = rpc_network_info.target_height;
local_copy.difficulty = rpc_network_info.difficulty;
local_copy.difficulty_top64 = rpc_network_info.difficulty_top64;
local_copy.target = rpc_network_info.target;
local_copy.hash_rate = (rpc_network_info.difficulty/300);
cryptonote::difficulty_type hash_rate = cryptonote::difficulty_type(rpc_network_info.wide_difficulty) / rpc_network_info.target;
local_copy.hash_rate = (hash_rate & 0xFFFFFFFFFFFFFFFF).convert_to<uint64_t>();
local_copy.hash_rate_top64 = ((hash_rate >> 64) & 0xFFFFFFFFFFFFFFFF).convert_to<uint64_t>();
local_copy.tx_count = rpc_network_info.tx_count;
local_copy.tx_pool_size = rpc_network_info.tx_pool_size;
local_copy.alt_blocks_count = rpc_network_info.alt_blocks_count;
@ -286,6 +289,7 @@ MempoolStatus::read_network_info()
local_copy.nettype = rpc_network_info.testnet ? cryptonote::network_type::TESTNET :
rpc_network_info.stagenet ? cryptonote::network_type::STAGENET : cryptonote::network_type::MAINNET;
local_copy.cumulative_difficulty = rpc_network_info.cumulative_difficulty;
local_copy.cumulative_difficulty_top64 = rpc_network_info.cumulative_difficulty_top64;
local_copy.block_size_limit = rpc_network_info.block_size_limit;
local_copy.block_size_median = rpc_network_info.block_size_median;
local_copy.block_weight_limit = rpc_network_info.block_weight_limit;

View file

@ -61,6 +61,7 @@ struct MempoolStatus
uint64_t height {0};
uint64_t target_height {0};
uint64_t difficulty {0};
uint64_t difficulty_top64 {0};
uint64_t target {0};
uint64_t tx_count {0};
uint64_t tx_pool_size {0};
@ -72,6 +73,7 @@ struct MempoolStatus
cryptonote::network_type nettype {cryptonote::network_type::MAINNET};
crypto::hash top_block_hash;
uint64_t cumulative_difficulty {0};
uint64_t cumulative_difficulty_top64 {0};
uint64_t block_size_limit {0};
uint64_t block_size_median {0};
uint64_t block_weight_limit {0};
@ -81,6 +83,7 @@ struct MempoolStatus
uint64_t current_hf_version {0};
uint64_t hash_rate {0};
uint64_t hash_rate_top64 {0};
uint64_t fee_per_kb {0};
uint64_t info_timestamp {0};

View file

@ -137,13 +137,31 @@ MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
if (m_blockchain_storage.have_tx(tx_hash))
{
// get transaction with given hash
tx = m_blockchain_storage.get_db().get_tx(tx_hash);
try
{
tx = m_blockchain_storage.get_db().get_tx(tx_hash);
}
catch (TX_DNE const& e)
{
try
{
// coinbase txs are not considered pruned
tx = m_blockchain_storage.get_db().get_pruned_tx(tx_hash);
return true;
}
catch (TX_DNE const& e)
{
cerr << "MicroCore::get_tx: " << e.what() << endl;
}
return false;
}
}
else
{
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
return false;
}
}
return true;

14
src/crypto/CMakeLists.txt Normal file
View file

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 2.8)
project(mycrypto)
set(SOURCE_FILES
rx-slow-hash.c)
# make static library called libmyxrm
# that we are going to link to
# in the root CMakeLists.txt file
add_library(mycrypto
STATIC
${SOURCE_FILES})

349
src/crypto/rx-slow-hash.c Normal file
View file

@ -0,0 +1,349 @@
// Copyright (c) 2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "randomx.h"
#include "c_threads.h"
#include "hash-ops.h"
#include "misc_log_ex.h"
#define RX_LOGCAT "randomx"
#if defined(_MSC_VER)
#define THREADV __declspec(thread)
#else
#define THREADV __thread
#endif
typedef struct rx_state {
CTHR_MUTEX_TYPE rs_mutex;
char rs_hash[32];
uint64_t rs_height;
randomx_cache *rs_cache;
} rx_state;
static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT;
static CTHR_MUTEX_TYPE rx_dataset_mutex = CTHR_MUTEX_INIT;
static rx_state rx_s[2] = {{CTHR_MUTEX_INIT,{0},0,0},{CTHR_MUTEX_INIT,{0},0,0}};
static randomx_dataset *rx_dataset;
static uint64_t rx_dataset_height;
THREADV randomx_vm *rx_vm = NULL;
static THREADV int rx_toggle;
static void local_abort(const char *msg)
{
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
/**
* @brief uses cpuid to determine if the CPU supports the AES instructions
* @return true if the CPU supports AES, false otherwise
*/
static inline int force_software_aes(void)
{
static int use = -1;
if (use != -1)
return use;
const char *env = getenv("MONERO_USE_SOFTWARE_AES");
if (!env) {
use = 0;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use = 0;
}
else {
use = 1;
}
return use;
}
static void cpuid(int CPUInfo[4], int InfoType)
{
#if defined(__x86_64__)
__asm __volatile__
(
"cpuid":
"=a" (CPUInfo[0]),
"=b" (CPUInfo[1]),
"=c" (CPUInfo[2]),
"=d" (CPUInfo[3]) :
"a" (InfoType), "c" (0)
);
#endif
}
static inline int check_aes_hw(void)
{
#if defined(__x86_64__)
int cpuid_results[4];
static int supported = -1;
if(supported >= 0)
return supported;
cpuid(cpuid_results,1);
return supported = cpuid_results[2] & (1 << 25);
#else
return 0;
#endif
}
static volatile int use_rx_jit_flag = -1;
static inline int use_rx_jit(void)
{
#if defined(__x86_64__)
if (use_rx_jit_flag != -1)
return use_rx_jit_flag;
const char *env = getenv("MONERO_USE_RX_JIT");
if (!env) {
use_rx_jit_flag = 1;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use_rx_jit_flag = 0;
}
else {
use_rx_jit_flag = 1;
}
return use_rx_jit_flag;
#else
return 0;
#endif
}
#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
#define SEEDHASH_EPOCH_LAG 64
void me_rx_reorg(const uint64_t split_height) {
int i;
CTHR_MUTEX_LOCK(rx_mutex);
for (i=0; i<2; i++) {
if (split_height < rx_s[i].rs_height)
rx_s[i].rs_height = 1; /* set to an invalid seed height */
}
CTHR_MUTEX_UNLOCK(rx_mutex);
}
uint64_t me_rx_seedheight(const uint64_t height) {
uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 :
(height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1);
return s_height;
}
void me_rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
*seedheight = me_rx_seedheight(height);
*nextheight = me_rx_seedheight(height + SEEDHASH_EPOCH_LAG);
}
typedef struct seedinfo {
randomx_cache *si_cache;
unsigned long si_start;
unsigned long si_count;
} seedinfo;
static CTHR_THREAD_RTYPE rx_seedthread(void *arg) {
seedinfo *si = arg;
randomx_init_dataset(rx_dataset, si->si_cache, si->si_start, si->si_count);
CTHR_THREAD_RETURN;
}
static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_t seedheight) {
if (miners > 1) {
unsigned long delta = randomx_dataset_item_count() / miners;
unsigned long start = 0;
int i;
seedinfo *si;
CTHR_THREAD_TYPE *st;
si = malloc(miners * sizeof(seedinfo));
if (si == NULL)
local_abort("Couldn't allocate RandomX mining threadinfo");
st = malloc(miners * sizeof(CTHR_THREAD_TYPE));
if (st == NULL) {
free(si);
local_abort("Couldn't allocate RandomX mining threadlist");
}
for (i=0; i<miners-1; i++) {
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = delta;
start += delta;
}
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = randomx_dataset_item_count() - start;
for (i=1; i<miners; i++) {
CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]);
}
randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count);
for (i=1; i<miners; i++) {
CTHR_THREAD_JOIN(st[i]);
}
free(st);
free(si);
} else {
randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count());
}
rx_dataset_height = seedheight;
}
void me_rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length,
char *hash, int miners, int is_alt) {
uint64_t s_height = me_rx_seedheight(mainheight);
int changed = 0;
int toggle = is_alt ? s_height : seedheight;
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
rx_state *rx_sp;
randomx_cache *cache;
toggle = (toggle & SEEDHASH_EPOCH_BLOCKS) != 0;
CTHR_MUTEX_LOCK(rx_mutex);
/* if alt block but with same seed as mainchain, no need for alt cache */
if (is_alt && s_height == seedheight && !memcmp(rx_s[toggle].rs_hash, seedhash, sizeof(rx_s[toggle].rs_hash)))
is_alt = 0;
/* RPC could request an earlier block on mainchain */
if (!is_alt && s_height > seedheight)
is_alt = 1;
toggle ^= (is_alt != 0);
if (toggle != rx_toggle)
changed = 1;
rx_toggle = toggle;
rx_sp = &rx_s[toggle];
CTHR_MUTEX_LOCK(rx_sp->rs_mutex);
CTHR_MUTEX_UNLOCK(rx_mutex);
cache = rx_sp->rs_cache;
if (cache == NULL) {
if (use_rx_jit())
flags |= RANDOMX_FLAG_JIT;
if (cache == NULL) {
cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
if (cache == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache");
cache = randomx_alloc_cache(flags);
}
if (cache == NULL)
local_abort("Couldn't allocate RandomX cache");
}
}
if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(seedhash, rx_sp->rs_hash, sizeof(rx_sp->rs_hash))) {
randomx_init_cache(cache, seedhash, 32);
rx_sp->rs_cache = cache;
rx_sp->rs_height = seedheight;
memcpy(rx_sp->rs_hash, seedhash, sizeof(rx_sp->rs_hash));
changed = 1;
}
if (rx_vm == NULL) {
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
if (use_rx_jit()) {
flags |= RANDOMX_FLAG_JIT;
if (!miners)
flags |= RANDOMX_FLAG_SECURE;
}
if(!force_software_aes() && check_aes_hw())
flags |= RANDOMX_FLAG_HARD_AES;
if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (rx_dataset == NULL) {
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES);
if (rx_dataset == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset");
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
}
if (rx_dataset != NULL)
rx_initdata(rx_sp->rs_cache, miners, seedheight);
}
if (rx_dataset != NULL)
flags |= RANDOMX_FLAG_FULL_MEM;
else {
miners = 0;
mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner");
}
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
}
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) { //large pages failed
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM");
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if(rx_vm == NULL) {//fallback if everything fails
flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0);
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if (rx_vm == NULL)
local_abort("Couldn't allocate RandomX VM");
} else if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (rx_dataset != NULL && rx_dataset_height != seedheight)
rx_initdata(cache, miners, seedheight);
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
} else if (changed) {
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache);
}
/* mainchain users can run in parallel */
if (!is_alt)
CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex);
randomx_calculate_hash(rx_vm, data, length, hash);
/* altchain slot users always get fully serialized */
if (is_alt)
CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex);
}
void me_rx_slow_hash_allocate_state(void) {
}
void me_rx_slow_hash_free_state(void) {
if (rx_vm != NULL) {
randomx_destroy_vm(rx_vm);
rx_vm = NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,13 @@
</tr>
<tr>
<td>PoW hash:</td><td>{{blk_pow_hash}}</td>
<td>Difficulty (hi64, lo64):</td><td>{{blk_difficulty_hi}}, {{blk_difficulty_lo}}</td>
<td>Difficulty:</td><td>{{blk_difficulty}}</td>
{{#is_randomx}}
<td colspan="2"><a href="/randomx/{{blk_height}}">RandomWOW source code</a></td>
{{/is_randomx}}
{{^is_randomx}}
<td></td>
{{/is_randomx}}
<td></td>
</tr>
</table>

View file

@ -13,15 +13,13 @@
{{#css_styles}}{{/css_styles}}
</style>
{{#js_files}}{{/js_files}}
</head>
<body>
<div>
<div class="center">
<h1 class="center"><a href="/">Wownero Blockchain Explorer</a></h1>
<h4 style="font-size: 15px; margin: 0px">({{^enable_js}}no javascript - {{/enable_js}}no cookies - no web analytics trackers - no images - open sourced)</h4>
<h1 class="center"><a href="/">Onion Wownero Blockchain Explorer</a></h1>
<h4 style="font-size: 15px; margin: 0px">(no javascript - no cookies - no web analytics trackers - no images - open sourced)</h4>
</div>

View file

@ -111,14 +111,3 @@
</div>
{{#show_cache_times}}
<div class="center">
<h6 style="margin-top: 1px;color:#949490">
Tx details construction time: {{construction_time_total}} s
<br/>
includes {{construction_time_cached}} s from block cache ({{cache_hits}} hits)
and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses)
</h6>
</div>
{{/show_cache_times}}

View file

@ -1,190 +0,0 @@
var cnBase58 = (function () {
var b58 = {};
var alphabet_str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var alphabet = [];
for (var i = 0; i < alphabet_str.length; i++) {
alphabet.push(alphabet_str.charCodeAt(i));
}
var encoded_block_sizes = [0, 2, 3, 5, 6, 7, 9, 10, 11];
var alphabet_size = alphabet.length;
var full_block_size = 8;
var full_encoded_block_size = 11;
var UINT64_MAX = new JSBigInt(2).pow(64);
function hextobin(hex) {
if (hex.length % 2 !== 0) throw "Hex string has invalid length!";
var res = new Uint8Array(hex.length / 2);
for (var i = 0; i < hex.length / 2; ++i) {
res[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
}
return res;
}
function bintohex(bin) {
var out = [];
for (var i = 0; i < bin.length; ++i) {
out.push(("0" + bin[i].toString(16)).slice(-2));
}
return out.join("");
}
function strtobin(str) {
var res = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) {
res[i] = str.charCodeAt(i);
}
return res;
}
function bintostr(bin) {
var out = [];
for (var i = 0; i < bin.length; i++) {
out.push(String.fromCharCode(bin[i]));
}
return out.join("");
}
function uint8_be_to_64(data) {
if (data.length < 1 || data.length > 8) {
throw "Invalid input length";
}
var res = JSBigInt.ZERO;
var twopow8 = new JSBigInt(2).pow(8);
var i = 0;
switch (9 - data.length) {
case 1:
res = res.add(data[i++]);
case 2:
res = res.multiply(twopow8).add(data[i++]);
case 3:
res = res.multiply(twopow8).add(data[i++]);
case 4:
res = res.multiply(twopow8).add(data[i++]);
case 5:
res = res.multiply(twopow8).add(data[i++]);
case 6:
res = res.multiply(twopow8).add(data[i++]);
case 7:
res = res.multiply(twopow8).add(data[i++]);
case 8:
res = res.multiply(twopow8).add(data[i++]);
break;
default:
throw "Impossible condition";
}
return res;
}
function uint64_to_8be(num, size) {
var res = new Uint8Array(size);
if (size < 1 || size > 8) {
throw "Invalid input length";
}
var twopow8 = new JSBigInt(2).pow(8);
for (var i = size - 1; i >= 0; i--) {
res[i] = num.remainder(twopow8).toJSValue();
num = num.divide(twopow8);
}
return res;
}
b58.encode_block = function (data, buf, index) {
if (data.length < 1 || data.length > full_encoded_block_size) {
throw "Invalid block length: " + data.length;
}
var num = uint8_be_to_64(data);
var i = encoded_block_sizes[data.length] - 1;
// while num > 0
while (num.compare(0) === 1) {
var div = num.divRem(alphabet_size);
// remainder = num % alphabet_size
var remainder = div[1];
// num = num / alphabet_size
num = div[0];
buf[index + i] = alphabet[remainder.toJSValue()];
i--;
}
return buf;
};
b58.encode = function (hex) {
var data = hextobin(hex);
if (data.length === 0) {
return "";
}
var full_block_count = Math.floor(data.length / full_block_size);
var last_block_size = data.length % full_block_size;
var res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size];
var res = new Uint8Array(res_size);
var i;
for (i = 0; i < res_size; ++i) {
res[i] = alphabet[0];
}
for (i = 0; i < full_block_count; i++) {
res = b58.encode_block(data.subarray(i * full_block_size, i * full_block_size + full_block_size), res, i * full_encoded_block_size);
}
if (last_block_size > 0) {
res = b58.encode_block(data.subarray(full_block_count * full_block_size, full_block_count * full_block_size + last_block_size), res, full_block_count * full_encoded_block_size)
}
return bintostr(res);
};
b58.decode_block = function (data, buf, index) {
if (data.length < 1 || data.length > full_encoded_block_size) {
throw "Invalid block length: " + data.length;
}
var res_size = encoded_block_sizes.indexOf(data.length);
if (res_size <= 0) {
throw "Invalid block size";
}
var res_num = new JSBigInt(0);
var order = new JSBigInt(1);
for (var i = data.length - 1; i >= 0; i--) {
var digit = alphabet.indexOf(data[i]);
if (digit < 0) {
throw "Invalid symbol";
}
var product = order.multiply(digit).add(res_num);
// if product > UINT64_MAX
if (product.compare(UINT64_MAX) === 1) {
throw "Overflow";
}
res_num = product;
order = order.multiply(alphabet_size);
}
if (res_size < full_block_size && (new JSBigInt(2).pow(8 * res_size).compare(res_num) <= 0)) {
throw "Overflow 2";
}
buf.set(uint64_to_8be(res_num, res_size), index);
return buf;
};
b58.decode = function (enc) {
enc = strtobin(enc);
if (enc.length === 0) {
return "";
}
var full_block_count = Math.floor(enc.length / full_encoded_block_size);
var last_block_size = enc.length % full_encoded_block_size;
var last_block_decoded_size = encoded_block_sizes.indexOf(last_block_size);
if (last_block_decoded_size < 0) {
throw "Invalid encoded length";
}
var data_size = full_block_count * full_block_size + last_block_decoded_size;
var data = new Uint8Array(data_size);
for (var i = 0; i < full_block_count; i++) {
data = b58.decode_block(enc.subarray(i * full_encoded_block_size, i * full_encoded_block_size + full_encoded_block_size), data, i * full_block_size);
}
if (last_block_size > 0) {
data = b58.decode_block(enc.subarray(full_block_count * full_encoded_block_size, full_block_count * full_encoded_block_size + last_block_size), data, full_block_count * full_block_size);
}
return bintohex(data);
};
return b58;
})();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,65 +0,0 @@
var crc32 = (function () {
'use strict';
var crc32 = {};
crc32.Utf8Encode = function (string) {
return unescape(encodeURIComponent(string));
};
crc32.run = function (str) {
var crc = new crc32.Type();
crc.processString(str);
return crc.checksum();
};
crc32.table = [
0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035,
249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049,
498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639,
325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317,
997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443,
901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665,
651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303,
671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565,
1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059,
2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297,
1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223,
1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405,
1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995,
1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649,
1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015,
1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989,
3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523,
3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377,
4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879,
4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637,
3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859,
3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161,
3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815,
3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221,
2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371,
2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881,
2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567,
2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701,
2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035,
2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897,
3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431,
3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117
];
crc32.Type = function () {
this.rem_ = 0xFFFFFFFF;
this.checksum = function () {
return ((this.rem_ ^ 0xFFFFFFFF) >>> 0);
};
this.processString = function (str) {
str = crc32.Utf8Encode(str);
for (var i = 0; i < str.length; i++) {
var byte_index = ((str.charCodeAt(i) ^ this.rem_) >>> 0) & 0xFF;
this.rem_ = ((this.rem_ >>> 8) ^ crc32.table[byte_index]) >>> 0;
}
};
return this;
};
return crc32;
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,571 +0,0 @@
(function(nacl) {
'use strict';
// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.
// Public domain.
//
// Implementation derived from TweetNaCl version 20140427.
// See for details: http://tweetnacl.cr.yp.to/
// modified 2017 for some CN functions by luigi1111
var gf = function(init) {
var i, r = new Float64Array(16);
if (init) for (i = 0; i < init.length; i++) r[i] = init[i];
return r;
};
// Pluggable, initialized in high-level API below.
var randombytes = function(/* x, n */) { throw new Error('no PRNG'); };
var _0 = new Uint8Array(16);
var _9 = new Uint8Array(32); _9[0] = 9;
var gf0 = gf(),
gf1 = gf([1]),
_121665 = gf([0xdb41, 1]),
D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),
D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]),
X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]),
Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]),
I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);
function vn(x, xi, y, yi, n) {
var i,d = 0;
for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i];
return (1 & ((d - 1) >>> 8)) - 1;
}
function crypto_verify_16(x, xi, y, yi) {
return vn(x,xi,y,yi,16);
}
function crypto_verify_32(x, xi, y, yi) {
return vn(x,xi,y,yi,32);
}
function set25519(r, a) {
var i;
for (i = 0; i < 16; i++) r[i] = a[i]|0;
}
function car25519(o) {
var i, v, c = 1;
for (i = 0; i < 16; i++) {
v = o[i] + c + 65535;
c = Math.floor(v / 65536);
o[i] = v - c * 65536;
}
o[0] += c-1 + 37 * (c-1);
}
function sel25519(p, q, b) {
var t, c = ~(b-1);
for (var i = 0; i < 16; i++) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
function pack25519(o, n) {
var i, j, b;
var m = gf(), t = gf();
for (i = 0; i < 16; i++) t[i] = n[i];
car25519(t);
car25519(t);
car25519(t);
for (j = 0; j < 2; j++) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; i++) {
m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);
m[i-1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);
b = (m[15]>>16) & 1;
m[14] &= 0xffff;
sel25519(t, m, 1-b);
}
for (i = 0; i < 16; i++) {
o[2*i] = t[i] & 0xff;
o[2*i+1] = t[i]>>8;
}
}
function neq25519(a, b) {
var c = new Uint8Array(32), d = new Uint8Array(32);
pack25519(c, a);
pack25519(d, b);
return crypto_verify_32(c, 0, d, 0);
}
function par25519(a) {
var d = new Uint8Array(32);
pack25519(d, a);
return d[0] & 1;
}
function unpack25519(o, n) {
var i;
for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);
o[15] &= 0x7fff;
}
function A(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] + b[i];
}
function Z(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] - b[i];
}
function M(o, a, b) {
var v, c,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,
t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,
t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,
b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5],
b6 = b[6], b7 = b[7], b8 = b[8], b9 = b[9], b10 = b[10],
b11 = b[11], b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
v = a[0];
t0 += v * b0; t1 += v * b1; t2 += v * b2; t3 += v * b3;
t4 += v * b4; t5 += v * b5; t6 += v * b6; t7 += v * b7;
t8 += v * b8; t9 += v * b9; t10 += v * b10; t11 += v * b11;
t12 += v * b12; t13 += v * b13; t14 += v * b14; t15 += v * b15;
v = a[1];
t1 += v * b0; t2 += v * b1; t3 += v * b2; t4 += v * b3;
t5 += v * b4; t6 += v * b5; t7 += v * b6; t8 += v * b7;
t9 += v * b8; t10 += v * b9; t11 += v * b10; t12 += v * b11;
t13 += v * b12; t14 += v * b13; t15 += v * b14; t16 += v * b15;
v = a[2];
t2 += v * b0; t3 += v * b1; t4 += v * b2; t5 += v * b3;
t6 += v * b4; t7 += v * b5; t8 += v * b6; t9 += v * b7;
t10 += v * b8; t11 += v * b9; t12 += v * b10; t13 += v * b11;
t14 += v * b12; t15 += v * b13; t16 += v * b14; t17 += v * b15;
v = a[3];
t3 += v * b0; t4 += v * b1; t5 += v * b2; t6 += v * b3;
t7 += v * b4; t8 += v * b5; t9 += v * b6; t10 += v * b7;
t11 += v * b8; t12 += v * b9; t13 += v * b10; t14 += v * b11;
t15 += v * b12; t16 += v * b13; t17 += v * b14; t18 += v * b15;
v = a[4];
t4 += v * b0; t5 += v * b1; t6 += v * b2; t7 += v * b3;
t8 += v * b4; t9 += v * b5; t10 += v * b6; t11 += v * b7;
t12 += v * b8; t13 += v * b9; t14 += v * b10; t15 += v * b11;
t16 += v * b12; t17 += v * b13; t18 += v * b14; t19 += v * b15;
v = a[5];
t5 += v * b0; t6 += v * b1; t7 += v * b2; t8 += v * b3;
t9 += v * b4; t10 += v * b5; t11 += v * b6; t12 += v * b7;
t13 += v * b8; t14 += v * b9; t15 += v * b10; t16 += v * b11;
t17 += v * b12; t18 += v * b13; t19 += v * b14; t20 += v * b15;
v = a[6];
t6 += v * b0; t7 += v * b1; t8 += v * b2; t9 += v * b3;
t10 += v * b4; t11 += v * b5; t12 += v * b6; t13 += v * b7;
t14 += v * b8; t15 += v * b9; t16 += v * b10; t17 += v * b11;
t18 += v * b12; t19 += v * b13; t20 += v * b14; t21 += v * b15;
v = a[7];
t7 += v * b0; t8 += v * b1; t9 += v * b2; t10 += v * b3;
t11 += v * b4; t12 += v * b5; t13 += v * b6; t14 += v * b7;
t15 += v * b8; t16 += v * b9; t17 += v * b10; t18 += v * b11;
t19 += v * b12; t20 += v * b13; t21 += v * b14; t22 += v * b15;
v = a[8];
t8 += v * b0; t9 += v * b1; t10 += v * b2; t11 += v * b3;
t12 += v * b4; t13 += v * b5; t14 += v * b6; t15 += v * b7;
t16 += v * b8; t17 += v * b9; t18 += v * b10; t19 += v * b11;
t20 += v * b12; t21 += v * b13; t22 += v * b14; t23 += v * b15;
v = a[9];
t9 += v * b0; t10 += v * b1; t11 += v * b2; t12 += v * b3;
t13 += v * b4; t14 += v * b5; t15 += v * b6; t16 += v * b7;
t17 += v * b8; t18 += v * b9; t19 += v * b10; t20 += v * b11;
t21 += v * b12; t22 += v * b13; t23 += v * b14; t24 += v * b15;
v = a[10];
t10 += v * b0; t11 += v * b1; t12 += v * b2; t13 += v * b3;
t14 += v * b4; t15 += v * b5; t16 += v * b6; t17 += v * b7;
t18 += v * b8; t19 += v * b9; t20 += v * b10; t21 += v * b11;
t22 += v * b12; t23 += v * b13; t24 += v * b14; t25 += v * b15;
v = a[11];
t11 += v * b0; t12 += v * b1; t13 += v * b2; t14 += v * b3;
t15 += v * b4; t16 += v * b5; t17 += v * b6; t18 += v * b7;
t19 += v * b8; t20 += v * b9; t21 += v * b10; t22 += v * b11;
t23 += v * b12; t24 += v * b13; t25 += v * b14; t26 += v * b15;
v = a[12];
t12 += v * b0; t13 += v * b1; t14 += v * b2; t15 += v * b3;
t16 += v * b4; t17 += v * b5; t18 += v * b6; t19 += v * b7;
t20 += v * b8; t21 += v * b9; t22 += v * b10; t23 += v * b11;
t24 += v * b12; t25 += v * b13; t26 += v * b14; t27 += v * b15;
v = a[13];
t13 += v * b0; t14 += v * b1; t15 += v * b2; t16 += v * b3;
t17 += v * b4; t18 += v * b5; t19 += v * b6; t20 += v * b7;
t21 += v * b8; t22 += v * b9; t23 += v * b10; t24 += v * b11;
t25 += v * b12; t26 += v * b13; t27 += v * b14; t28 += v * b15;
v = a[14];
t14 += v * b0; t15 += v * b1; t16 += v * b2; t17 += v * b3;
t18 += v * b4; t19 += v * b5; t20 += v * b6; t21 += v * b7;
t22 += v * b8; t23 += v * b9; t24 += v * b10; t25 += v * b11;
t26 += v * b12; t27 += v * b13; t28 += v * b14; t29 += v * b15;
v = a[15];
t15 += v * b0; t16 += v * b1; t17 += v * b2; t18 += v * b3;
t19 += v * b4; t20 += v * b5; t21 += v * b6; t22 += v * b7;
t23 += v * b8; t24 += v * b9; t25 += v * b10; t26 += v * b11;
t27 += v * b12; t28 += v * b13; t29 += v * b14; t30 += v * b15;
t0 += 38 * t16; t1 += 38 * t17; t2 += 38 * t18; t3 += 38 * t19;
t4 += 38 * t20; t5 += 38 * t21; t6 += 38 * t22; t7 += 38 * t23;
t8 += 38 * t24; t9 += 38 * t25; t10 += 38 * t26; t11 += 38 * t27;
t12 += 38 * t28; t13 += 38 * t29; t14 += 38 * t30; // t15 left as is
// first car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
// second car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
o[ 0] = t0;
o[ 1] = t1;
o[ 2] = t2;
o[ 3] = t3;
o[ 4] = t4;
o[ 5] = t5;
o[ 6] = t6;
o[ 7] = t7;
o[ 8] = t8;
o[ 9] = t9;
o[10] = t10;
o[11] = t11;
o[12] = t12;
o[13] = t13;
o[14] = t14;
o[15] = t15;
}
function S(o, a) {
M(o, a, a);
}
function inv25519(o, i) {
var c = gf();
var a;
for (a = 0; a < 16; a++) c[a] = i[a];
for (a = 253; a >= 0; a--) {
S(c, c);
if(a !== 2 && a !== 4) M(c, c, i);
}
for (a = 0; a < 16; a++) o[a] = c[a];
}
function pow2523(o, i) {
var c = gf();
var a;
for (a = 0; a < 16; a++) c[a] = i[a];
for (a = 250; a >= 0; a--) {
S(c, c);
if(a !== 1) M(c, c, i);
}
for (a = 0; a < 16; a++) o[a] = c[a];
}
function add(p, q) {
var a = gf(), b = gf(), c = gf(),
d = gf(), e = gf(), f = gf(),
g = gf(), h = gf(), t = gf();
Z(a, p[1], p[0]);
Z(t, q[1], q[0]);
M(a, a, t);
A(b, p[0], p[1]);
A(t, q[0], q[1]);
M(b, b, t);
M(c, p[3], q[3]);
M(c, c, D2);
M(d, p[2], q[2]);
A(d, d, d);
Z(e, b, a);
Z(f, d, c);
A(g, d, c);
A(h, b, a);
M(p[0], e, f);
M(p[1], h, g);
M(p[2], g, f);
M(p[3], e, h);
}
function cswap(p, q, b) {
var i;
for (i = 0; i < 4; i++) {
sel25519(p[i], q[i], b);
}
}
function pack(r, p) {
var tx = gf(), ty = gf(), zi = gf();
inv25519(zi, p[2]);
M(tx, p[0], zi);
M(ty, p[1], zi);
pack25519(r, ty);
r[31] ^= par25519(tx) << 7;
}
function scalarmult(p, q, s) {
var b, i;
set25519(p[0], gf0);
set25519(p[1], gf1);
set25519(p[2], gf1);
set25519(p[3], gf0);
for (i = 255; i >= 0; --i) {
b = (s[(i/8)|0] >> (i&7)) & 1;
cswap(p, q, b);
add(q, p);
add(p, p);
cswap(p, q, b);
}
}
function scalarbase(p, s) {
var q = [gf(), gf(), gf(), gf()];
set25519(q[0], X);
set25519(q[1], Y);
set25519(q[2], gf1);
M(q[3], X, Y);
scalarmult(p, q, s);
}
//new functions for CN - scalar operations are handled externally
// this only handles curve operations, except for Hp()
//why do we negate points when unpacking them???
function ge_neg(pub) {
pub[31] ^= 0x80;
}
//res = s*G
function ge_scalarmult_base(s) {
var p = [gf(), gf(), gf(), gf()];
scalarbase(p, s);
var pk = new Uint8Array(32);
pack(pk, p);
return pk;
}
//res = s*P
function ge_scalarmult(P, s) {
var p = [gf(), gf(), gf(), gf()],
upk = [gf(), gf(), gf(), gf()],
res = new Uint8Array(32);
ge_neg(P);
if (unpackneg(upk, P) !== 0) throw "non-0 error on point decode";
scalarmult(p, upk, s);
pack(res, p);
return res;
}
//res = c*P + r*G
function ge_double_scalarmult_base_vartime(c, P, r) {
var uP = [gf(), gf(), gf(), gf()],
cP = [gf(), gf(), gf(), gf()],
rG = [gf(), gf(), gf(), gf()],
res = new Uint8Array(32);
ge_neg(P);
if (unpackneg(uP, P) !== 0) throw "non-0 error on point decode";
scalarmult(cP, uP, c);
scalarbase(rG, r);
add(rG, cP);
pack(res, rG);
return res;
}
//name changed to reflect not using precomp; res = r*Pb + c*I
function ge_double_scalarmult_postcomp_vartime(r, Pb, c, I) {
var uPb = [gf(), gf(), gf(), gf()],
uI = [gf(), gf(), gf(), gf()],
cI = [gf(), gf(), gf(), gf()],
rPb = [gf(), gf(), gf(), gf()],
res = new Uint8Array(32);
ge_neg(Pb);
if (unpackneg(uPb, Pb) !== 0) throw "non-0 error on point decode";
scalarmult(rPb, uPb, r);
ge_neg(I);
if (unpackneg(uI, I) !== 0) throw "non-0 error on point decode";
scalarmult(cI, uI, c);
add(rPb, cI);
pack(res, rPb);
return res;
}
//res = P + Q
function ge_add(P, Q) {
var uP = [gf(), gf(), gf(), gf()],
uQ = [gf(), gf(), gf(), gf()],
res = new Uint8Array(32);
ge_neg(P);
ge_neg(Q);
if (unpackneg(uP, P) !== 0) throw "non-0 error on point decode";
if (unpackneg(uQ, Q) !== 0) throw "non-0 error on point decode";
add(uP, uQ);
pack(res, uP);
return res;
}
var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]);
function modL(r, x) {
var carry, i, j, k;
for (i = 63; i >= 32; --i) {
carry = 0;
for (j = i - 32, k = i - 12; j < k; ++j) {
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
carry = (x[j] + 128) >> 8;
x[j] -= carry * 256;
}
x[j] += carry;
x[i] = 0;
}
carry = 0;
for (j = 0; j < 32; j++) {
x[j] += carry - (x[31] >> 4) * L[j];
carry = x[j] >> 8;
x[j] &= 255;
}
for (j = 0; j < 32; j++) x[j] -= carry * L[j];
for (i = 0; i < 32; i++) {
x[i+1] += x[i] >> 8;
r[i] = x[i] & 255;
}
}
function reduce(r) {
var x = new Float64Array(64), i;
for (i = 0; i < 64; i++) x[i] = r[i];
for (i = 0; i < 64; i++) r[i] = 0;
modL(r, x);
}
function unpackneg(r, p) {
var t = gf(), chk = gf(), num = gf(),
den = gf(), den2 = gf(), den4 = gf(),
den6 = gf();
set25519(r[2], gf1);
unpack25519(r[1], p);
S(num, r[1]);
M(den, num, D);
Z(num, num, r[2]);
A(den, r[2], den);
S(den2, den);
S(den4, den2);
M(den6, den4, den2);
M(t, den6, num);
M(t, t, den);
pow2523(t, t);
M(t, t, num);
M(t, t, den);
M(t, t, den);
M(r[0], t, den);
S(chk, r[0]);
M(chk, chk, den);
if (neq25519(chk, num)) M(r[0], r[0], I);
S(chk, r[0]);
M(chk, chk, den);
if (neq25519(chk, num)) return -1;
if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]);
M(r[3], r[0], r[1]);
return 0;
}
nacl.ll = {
ge_scalarmult_base: ge_scalarmult_base,
ge_scalarmult: ge_scalarmult,
ge_double_scalarmult_base_vartime: ge_double_scalarmult_base_vartime,
ge_add: ge_add,
ge_double_scalarmult_postcomp_vartime: ge_double_scalarmult_postcomp_vartime
};
/* High-level API */
function cleanup(arr) {
for (var i = 0; i < arr.length; i++) arr[i] = 0;
}
nacl.randomBytes = function(n) {
var b = new Uint8Array(n);
randombytes(b, n);
return b;
};
nacl.setPRNG = function(fn) {
randombytes = fn;
};
(function() {
// Initialize PRNG if environment provides CSPRNG.
// If not, methods calling randombytes will throw.
var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null;
if (crypto && crypto.getRandomValues) {
// Browsers.
var QUOTA = 65536;
nacl.setPRNG(function(x, n) {
var i, v = new Uint8Array(n);
for (i = 0; i < n; i += QUOTA) {
crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA)));
}
for (i = 0; i < n; i++) x[i] = v[i];
cleanup(v);
});
} else if (typeof require !== 'undefined') {
// Node.js.
crypto = require('crypto');
if (crypto && crypto.randomBytes) {
nacl.setPRNG(function(x, n) {
var i, v = crypto.randomBytes(n);
for (i = 0; i < n; i++) x[i] = v[i];
cleanup(v);
});
}
}
})();
})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {}));

View file

@ -1,473 +0,0 @@
/*
* js-sha3 v0.5.1
* https://github.com/emn178/js-sha3
*
* Copyright 2015, emn178@gmail.com
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/MIT
*/
;(function(root, undefined) {
'use strict';
var NODE_JS = typeof(module) != 'undefined';
if(NODE_JS) {
root = global;
if(root.JS_SHA3_TEST) {
root.navigator = { userAgent: 'Chrome'};
}
}
var HEX_CHARS = '0123456789abcdef'.split('');
var SHAKE_PADDING = [31, 7936, 2031616, 520093696];
var KECCAK_PADDING = [1, 256, 65536, 16777216];
var PADDING = [6, 1536, 393216, 100663296];
var SHIFT = [0, 8, 16, 24];
var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649,
0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0,
2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771,
2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648,
2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648];
var BITS = [224, 256, 384, 512];
var SHAKE_BITS = [128, 256];
var OUTPUT_TYPES = ['hex', 'buffer', 'array'];
var createOutputMethod = function(bits, padding, outputType) {
return function(message) {
return new Keccak(bits, padding, bits).update(message)[outputType]();
}
};
var createShakeOutputMethod = function(bits, padding, outputType) {
return function(message, outputBits) {
return new Keccak(bits, padding, outputBits).update(message)[outputType]();
}
};
var createMethod = function(bits, padding) {
var method = createOutputMethod(bits, padding, 'hex');
method.create = function() {
return new Keccak(bits, padding, bits);
};
method.update = function(message) {
return method.create().update(message);
};
for(var i = 0;i < OUTPUT_TYPES.length;++i) {
var type = OUTPUT_TYPES[i];
method[type] = createOutputMethod(bits, padding, type);
}
return method;
};
var createShakeMethod = function(bits, padding) {
var method = createShakeOutputMethod(bits, padding, 'hex');
method.create = function(outputBits) {
return new Keccak(bits, padding, outputBits);
};
method.update = function(message, outputBits) {
return method.create(outputBits).update(message);
};
for(var i = 0;i < OUTPUT_TYPES.length;++i) {
var type = OUTPUT_TYPES[i];
method[type] = createShakeOutputMethod(bits, padding, type);
}
return method;
};
var algorithms = [
{name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod},
{name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod},
{name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod}
];
var methods = {};
for(var i = 0;i < algorithms.length;++i) {
var algorithm = algorithms[i];
var bits = algorithm.bits;
var createMethod = algorithm.createMethod;
for(var j = 0;j < bits.length;++j) {
var method = algorithm.createMethod(bits[j], algorithm.padding);
methods[algorithm.name +'_' + bits[j]] = method;
}
}
function Keccak(bits, padding, outputBits) {
this.blocks = [];
this.s = [];
this.padding = padding;
this.outputBits = outputBits;
this.reset = true;
this.block = 0;
this.start = 0;
this.blockCount = (1600 - (bits << 1)) >> 5;
this.byteCount = this.blockCount << 2;
this.outputBlocks = outputBits >> 5;
this.extraBytes = (outputBits & 31) >> 3;
for(var i = 0;i < 50;++i) {
this.s[i] = 0;
}
};
Keccak.prototype.update = function(message) {
var notString = typeof(message) != 'string';
if(notString && message.constructor == root.ArrayBuffer) {
message = new Uint8Array(message);
}
var length = message.length, blocks = this.blocks, byteCount = this.byteCount,
blockCount = this.blockCount, index = 0, s = this.s, i, code;
while(index < length) {
if(this.reset) {
this.reset = false;
blocks[0] = this.block;
for(i = 1;i < blockCount + 1;++i) {
blocks[i] = 0;
}
}
if(notString) {
for (i = this.start;index < length && i < byteCount; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
}
} else {
for (i = this.start;index < length && i < byteCount; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
} else if (code < 0x800) {
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else if (code < 0xd800 || code >= 0xe000) {
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
}
}
}
this.lastByteIndex = i;
if(i >= byteCount) {
this.start = i - byteCount;
this.block = blocks[blockCount];
for(i = 0;i < blockCount;++i) {
s[i] ^= blocks[i];
}
f(s);
this.reset = true;
} else {
this.start = i;
}
}
return this;
};
Keccak.prototype.finalize = function() {
var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s;
blocks[i >> 2] |= this.padding[i & 3];
if(this.lastByteIndex == this.byteCount) {
blocks[0] = blocks[blockCount];
for(i = 1;i < blockCount + 1;++i) {
blocks[i] = 0;
}
}
blocks[blockCount - 1] |= 0x80000000;
for(i = 0;i < blockCount;++i) {
s[i] ^= blocks[i];
}
f(s);
};
Keccak.prototype.toString = Keccak.prototype.hex = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var hex = '', block;
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
block = s[i];
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] +
HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] +
HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] +
HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F];
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
block = s[i];
if(extraBytes > 0) {
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F];
}
if(extraBytes > 1) {
hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F];
}
if(extraBytes > 2) {
hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F];
}
}
return hex;
};
Keccak.prototype.buffer = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var bytes = this.outputBits >> 3;
var buffer;
if(extraBytes) {
buffer = new ArrayBuffer((outputBlocks + 1) << 2);
} else {
buffer = new ArrayBuffer(bytes);
}
var array = new Uint32Array(buffer);
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
array[j] = s[i];
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
array[i] = s[i];
buffer = buffer.slice(0, bytes);
}
return buffer;
};
Keccak.prototype.digest = Keccak.prototype.array = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var array = [], offset, block;
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
offset = j << 2;
block = s[i];
array[offset] = block & 0xFF;
array[offset + 1] = (block >> 8) & 0xFF;
array[offset + 2] = (block >> 16) & 0xFF;
array[offset + 3] = (block >> 24) & 0xFF;
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
offset = j << 2;
block = s[i];
if(extraBytes > 0) {
array[offset] = block & 0xFF;
}
if(extraBytes > 1) {
array[offset + 1] = (block >> 8) & 0xFF;
}
if(extraBytes > 2) {
array[offset + 2] = (block >> 16) & 0xFF;
}
}
return array;
};
var f = function(s) {
var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9,
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17,
b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33,
b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49;
for(n = 0; n < 48; n += 2) {
c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
h = c8 ^ ((c2 << 1) | (c3 >>> 31));
l = c9 ^ ((c3 << 1) | (c2 >>> 31));
s[0] ^= h;
s[1] ^= l;
s[10] ^= h;
s[11] ^= l;
s[20] ^= h;
s[21] ^= l;
s[30] ^= h;
s[31] ^= l;
s[40] ^= h;
s[41] ^= l;
h = c0 ^ ((c4 << 1) | (c5 >>> 31));
l = c1 ^ ((c5 << 1) | (c4 >>> 31));
s[2] ^= h;
s[3] ^= l;
s[12] ^= h;
s[13] ^= l;
s[22] ^= h;
s[23] ^= l;
s[32] ^= h;
s[33] ^= l;
s[42] ^= h;
s[43] ^= l;
h = c2 ^ ((c6 << 1) | (c7 >>> 31));
l = c3 ^ ((c7 << 1) | (c6 >>> 31));
s[4] ^= h;
s[5] ^= l;
s[14] ^= h;
s[15] ^= l;
s[24] ^= h;
s[25] ^= l;
s[34] ^= h;
s[35] ^= l;
s[44] ^= h;
s[45] ^= l;
h = c4 ^ ((c8 << 1) | (c9 >>> 31));
l = c5 ^ ((c9 << 1) | (c8 >>> 31));
s[6] ^= h;
s[7] ^= l;
s[16] ^= h;
s[17] ^= l;
s[26] ^= h;
s[27] ^= l;
s[36] ^= h;
s[37] ^= l;
s[46] ^= h;
s[47] ^= l;
h = c6 ^ ((c0 << 1) | (c1 >>> 31));
l = c7 ^ ((c1 << 1) | (c0 >>> 31));
s[8] ^= h;
s[9] ^= l;
s[18] ^= h;
s[19] ^= l;
s[28] ^= h;
s[29] ^= l;
s[38] ^= h;
s[39] ^= l;
s[48] ^= h;
s[49] ^= l;
b0 = s[0];
b1 = s[1];
b32 = (s[11] << 4) | (s[10] >>> 28);
b33 = (s[10] << 4) | (s[11] >>> 28);
b14 = (s[20] << 3) | (s[21] >>> 29);
b15 = (s[21] << 3) | (s[20] >>> 29);
b46 = (s[31] << 9) | (s[30] >>> 23);
b47 = (s[30] << 9) | (s[31] >>> 23);
b28 = (s[40] << 18) | (s[41] >>> 14);
b29 = (s[41] << 18) | (s[40] >>> 14);
b20 = (s[2] << 1) | (s[3] >>> 31);
b21 = (s[3] << 1) | (s[2] >>> 31);
b2 = (s[13] << 12) | (s[12] >>> 20);
b3 = (s[12] << 12) | (s[13] >>> 20);
b34 = (s[22] << 10) | (s[23] >>> 22);
b35 = (s[23] << 10) | (s[22] >>> 22);
b16 = (s[33] << 13) | (s[32] >>> 19);
b17 = (s[32] << 13) | (s[33] >>> 19);
b48 = (s[42] << 2) | (s[43] >>> 30);
b49 = (s[43] << 2) | (s[42] >>> 30);
b40 = (s[5] << 30) | (s[4] >>> 2);
b41 = (s[4] << 30) | (s[5] >>> 2);
b22 = (s[14] << 6) | (s[15] >>> 26);
b23 = (s[15] << 6) | (s[14] >>> 26);
b4 = (s[25] << 11) | (s[24] >>> 21);
b5 = (s[24] << 11) | (s[25] >>> 21);
b36 = (s[34] << 15) | (s[35] >>> 17);
b37 = (s[35] << 15) | (s[34] >>> 17);
b18 = (s[45] << 29) | (s[44] >>> 3);
b19 = (s[44] << 29) | (s[45] >>> 3);
b10 = (s[6] << 28) | (s[7] >>> 4);
b11 = (s[7] << 28) | (s[6] >>> 4);
b42 = (s[17] << 23) | (s[16] >>> 9);
b43 = (s[16] << 23) | (s[17] >>> 9);
b24 = (s[26] << 25) | (s[27] >>> 7);
b25 = (s[27] << 25) | (s[26] >>> 7);
b6 = (s[36] << 21) | (s[37] >>> 11);
b7 = (s[37] << 21) | (s[36] >>> 11);
b38 = (s[47] << 24) | (s[46] >>> 8);
b39 = (s[46] << 24) | (s[47] >>> 8);
b30 = (s[8] << 27) | (s[9] >>> 5);
b31 = (s[9] << 27) | (s[8] >>> 5);
b12 = (s[18] << 20) | (s[19] >>> 12);
b13 = (s[19] << 20) | (s[18] >>> 12);
b44 = (s[29] << 7) | (s[28] >>> 25);
b45 = (s[28] << 7) | (s[29] >>> 25);
b26 = (s[38] << 8) | (s[39] >>> 24);
b27 = (s[39] << 8) | (s[38] >>> 24);
b8 = (s[48] << 14) | (s[49] >>> 18);
b9 = (s[49] << 14) | (s[48] >>> 18);
s[0] = b0 ^ (~b2 & b4);
s[1] = b1 ^ (~b3 & b5);
s[10] = b10 ^ (~b12 & b14);
s[11] = b11 ^ (~b13 & b15);
s[20] = b20 ^ (~b22 & b24);
s[21] = b21 ^ (~b23 & b25);
s[30] = b30 ^ (~b32 & b34);
s[31] = b31 ^ (~b33 & b35);
s[40] = b40 ^ (~b42 & b44);
s[41] = b41 ^ (~b43 & b45);
s[2] = b2 ^ (~b4 & b6);
s[3] = b3 ^ (~b5 & b7);
s[12] = b12 ^ (~b14 & b16);
s[13] = b13 ^ (~b15 & b17);
s[22] = b22 ^ (~b24 & b26);
s[23] = b23 ^ (~b25 & b27);
s[32] = b32 ^ (~b34 & b36);
s[33] = b33 ^ (~b35 & b37);
s[42] = b42 ^ (~b44 & b46);
s[43] = b43 ^ (~b45 & b47);
s[4] = b4 ^ (~b6 & b8);
s[5] = b5 ^ (~b7 & b9);
s[14] = b14 ^ (~b16 & b18);
s[15] = b15 ^ (~b17 & b19);
s[24] = b24 ^ (~b26 & b28);
s[25] = b25 ^ (~b27 & b29);
s[34] = b34 ^ (~b36 & b38);
s[35] = b35 ^ (~b37 & b39);
s[44] = b44 ^ (~b46 & b48);
s[45] = b45 ^ (~b47 & b49);
s[6] = b6 ^ (~b8 & b0);
s[7] = b7 ^ (~b9 & b1);
s[16] = b16 ^ (~b18 & b10);
s[17] = b17 ^ (~b19 & b11);
s[26] = b26 ^ (~b28 & b20);
s[27] = b27 ^ (~b29 & b21);
s[36] = b36 ^ (~b38 & b30);
s[37] = b37 ^ (~b39 & b31);
s[46] = b46 ^ (~b48 & b40);
s[47] = b47 ^ (~b49 & b41);
s[8] = b8 ^ (~b0 & b2);
s[9] = b9 ^ (~b1 & b3);
s[18] = b18 ^ (~b10 & b12);
s[19] = b19 ^ (~b11 & b13);
s[28] = b28 ^ (~b20 & b22);
s[29] = b29 ^ (~b21 & b23);
s[38] = b38 ^ (~b30 & b32);
s[39] = b39 ^ (~b31 & b33);
s[48] = b48 ^ (~b40 & b42);
s[49] = b49 ^ (~b41 & b43);
s[0] ^= RC[n];
s[1] ^= RC[n + 1];
}
}
if(!root.JS_SHA3_TEST && NODE_JS) {
module.exports = methods;
} else if(root) {
for(var key in methods) {
root[key] = methods[key];
}
}
}(this));

View file

@ -78,7 +78,7 @@
{{/found_our_outputs}}
</h3>
<h4>
<a href="{{shortcut_url}}" target="_blank">link to this page</a>
<a href="{{domain_url}}{{shortcut_url}}" target="_blank">link to this page</a>
</h4>
</div>

View file

@ -86,12 +86,7 @@
<h5 style="margin: 0px">
For RingCT transactions, outputs' amounts are also decoded
<br/>
{{#enable_js}}
Note: address/subaddress and viewkey are NOT sent to the server, as the calculations are done on the client side
{{/enable_js}}
{{^enable_js}}
Note: address/subaddress and viewkey are sent to the server, as the calculations are done on the server side
{{/enable_js}}
Note: address/subaddress and viewkey are sent to the server, as the calculations are done on the server side
</h5>
<form action="/myoutputs" method="post" style="width:100%; margin-top:2px" class="style-1">
<input type="hidden" name="tx_hash" value="{{tx_hash}}"><br/>
@ -99,15 +94,7 @@
<input type="text" name="viewkey" size="110" placeholder="Private viewkey" style="margin-top:5px"><br/>
<input type="hidden" name="raw_tx_data" value="{{raw_tx_data}}">
<!--above raw_tx_data field only used when checking raw tx data through tx pusher-->
{{#enable_js}}
<!-- if have js, DONOT submit the form to server.
change submit button, to just a button -->
<button type="button" style="margin-top:5px" id="decode_btn" >Decode outputs</button>
{{/enable_js}}
{{^enable_js}}
<input type="submit" value="Decode outputs" style="margin-top:5px" >
{{/enable_js}}
<input type="submit" value="Decode outputs" style="margin-top:5px" >
</form>
</div>
</div>
@ -122,29 +109,15 @@
Tx private key can be obtained using <i>get_tx_key</i>
command in <i>wownero-wallet-cli</i> command line tool
<br/>
{{#enable_js}}
Note: address/subaddress and tx private key are NOT sent to the server, as the calculations are done on the client side
{{/enable_js}}
{{^enable_js}}
Note: address/subaddress and tx private key are sent to the server, as the calculations are done on the server side
{{/enable_js}}
Note: address/subaddress and tx private key are sent to the server, as the calculations are done on the server side
</h5>
<form action="/prove" method="post" style="width:100%;margin-top:2px" class="style-1">
<input type="hidden" name="txhash" value="{{tx_hash}}"><br/>
<input type="text" name="txprvkey" size="120" placeholder="Tx private key"><br/>
<input type="hidden" name="raw_tx_data" value="{{raw_tx_data}}">
<!--above raw_tx_data field only used when checking raw tx data through tx pusher-->
<input type="text" name="xmraddress" size="120" placeholder="Recipient's wownero address/subaddress" style="margin-top:5px"><br/>
{{#enable_js}}
<!-- if have js, DONOT submit the form to server.
change submit button, to just a button -->
<button type="button" style="margin-top:5px" id="prove_btn">Prove sending</button>
{{/enable_js}}
{{^enable_js}}
<input type="submit" value="Prove sending" style="margin-top:5px">
{{/enable_js}}
<input type="text" name="xmraddress" size="120" placeholder="Recipient's monero address/subaddress" style="margin-top:5px"><br/>
<input type="submit" value="Prove sending" style="margin-top:5px">
</form>
</div>
</div>
@ -152,235 +125,6 @@
</div>
{{/have_raw_tx}}
{{#enable_js}}
<!-- to disply results from deconding and proving txs using js -->
<div id="decode-prove-results" class="center" style="width: 80%; margin-top:10px;border-style: dotted">
</div>
<script>
// here we handle button presses from the above forms
// to decode and prove txs.
$(document).ready(function() {
// we need output pubplic keys, their indexes and amounts.
// all this is already avaliable on the html, but we can use
// musch framework to produce js array for this
var tx_json = {{#tx_json_raw}}{{/tx_json_raw}};
var tx_public_key = $("#tx_pub_key").text();
// when we process multi-ouput tx, it can have extra public keys
// due to sub-addresses
var add_tx_pub_keys = $("#add_tx_pub_keys").text().split(';').slice(0, -1);
//console.log("add_tx_pub_keys: ", add_tx_pub_keys);
var payment_id = $("#payment_id").text();
$("#decode_btn").click(function() {
var address = $("input[name=xmr_address]").val().trim();
var viewkey = $("input[name=viewkey]").val().trim();
if (!address || !viewkey) {
$("#decode-prove-results").html("<h4>Address or viewkey key not provided!</h4>");
return;
}
// not used when decoding, but used when proving.
// so we just use array here
multiple_tx_secret_keys = [];
try {
var address_decoded = decode_address(address);
decodeOutputs(tx_json, tx_public_key, viewkey,
address_decoded.spend, payment_id,
add_tx_pub_keys, multiple_tx_secret_keys, false);
} catch(err){
console.log(err);
$("#decode-prove-results").html('<h4>Error: ' + err + '</h4>' );
}
});
$("#prove_btn").click(function() {
var address = $("input[name=xmraddress]").val().trim();
var tx_prv_key = $("input[name=txprvkey]").val().trim();
if (!address || !tx_prv_key) {
$("#decode-prove-results").html("<h4>Address or tx private key not provided!</h4>");
return;
}
try {
// when using subaddress, there can be more than one tx_prv_key
var multiple_tx_prv_keys = parse_str_secret_key(tx_prv_key);
var address_decoded = decode_address(address);
decodeOutputs(tx_json, address_decoded.view, tx_prv_key,
address_decoded.spend, payment_id,
add_tx_pub_keys, multiple_tx_prv_keys, true);
} catch(err){
console.log(err);
$("#decode-prove-results").html('<h4>Error: ' + err + '</h4>' );
}
});
});
// based on C++ code by stoffu
function parse_str_secret_key(key_str) {
var multiple_tx_secret_keys = [];
var num_keys = Math.floor(key_str.length / 64);
if (num_keys * 64 != key_str.length)
throw "num_keys * 64 != key_str.length";
for (var i = 0; i < num_keys; i++)
{
multiple_tx_secret_keys.push(key_str.slice(64*i, 64*i + 64));
}
return multiple_tx_secret_keys;
}
function decodeOutputs(tx_json, pub_key, sec_key,
address_pub_key, payment_id,
add_tx_pub_keys, multiple_tx_prv_keys, tx_prove) {
//console.log(tx_json);
var is_rct = (tx_json.version === 2);
var rct_type = (is_rct ? tx_json.rct_signatures.type : -1);
var key_derivation = "";
if (tx_prove)
key_derivation = generate_key_derivation(pub_key, multiple_tx_prv_keys[0]);
else
key_derivation = generate_key_derivation(pub_key, sec_key);
var add_key_derivation = [];
if (add_tx_pub_keys) {
for (var i = 0; i < add_tx_pub_keys.length; i++)
{
if (!tx_prove)
add_key_derivation.push(generate_key_derivation(add_tx_pub_keys[i], sec_key));
else
add_key_derivation.push(generate_key_derivation(pub_key, multiple_tx_prv_keys[i+1]));
}
}
//console.log("add_key_derivation: ", add_key_derivation);
// go over each tx output, and check if it is ours or not
var decoding_results_str = '<h3>Output decoding results</h3>';
decoding_results_str += '<table class="center">';
decoding_results_str += '<tr>' +
'<td></td>' +
'<td>output public key</td>' +
'<td>amount</td>' +
'<td>output match?</td>' +
'</tr>';
var output_idx = 0;
var sum_outptus = 0;
tx_json.vout.forEach(function(output) {
var output_pub_key = output.target.key;
var amount = output.amount;
var pubkey_generated = derive_public_key(key_derivation, output_idx, address_pub_key);
var mine_output = (output_pub_key == pubkey_generated);
var with_additional = false;
var mine_output_str = "false";
if (!mine_output && add_tx_pub_keys.length == tx_json.vout.length) {
pubkey_generated = derive_public_key(add_key_derivation[output_idx],
output_idx, address_pub_key);
mine_output = (output_pub_key == pubkey_generated);
with_additional = true;
}
if (mine_output) {
mine_output_str = '<span style="color: #008009;font-weight: bold">true</span>';
if (is_rct && rct_type > 0 /* not coinbase*/) {
try {
//var ecdh = decodeRct(tx_json.rct_signatures, output_idx, key_derivation);
var ecdh = decodeRct(tx_json.rct_signatures, output_idx,
(with_additional ? add_key_derivation[output_idx] : key_derivation));
amount = parseInt(ecdh.amount);
} catch (err) {
decoding_results_str += "<span class='validNo'>RingCT amount for output " + i + " with pubkey: " + output_pub_key + "</span>" + "<br>"; //rct commitment != computed
throw "invalid rct amount";
}
}
sum_outptus += amount;
}
decoding_results_str += "<tr>"
+"<td>" + output_idx + "</td>"
+"<td>" + output_pub_key + "</td>"
+"<td>" + (amount / 1e11) + "</td>"
+"<td>" + mine_output_str + "</td>"
+"</tr>";
//console.log(output[1], pubkey_generated);
output_idx++;
});
decoding_results_str += "</table>";
decoding_results_str += "<h3>Sum WOW from matched outputs (i.e., incoming WOW): " + (sum_outptus / 1e12) + "</h3>"
// decrypt payment_id8 which results in using
// integrated address
if (payment_id.length == 16) {
if (pub_key) {
var decrypted_payment_id8
= decrypt_payment_id(payment_id, pub_key, sec_key);
console.log("decrypted_payment_id8: " + decrypted_payment_id8);
decoding_results_str += "<h5>Decrypted payment id: "
+ decrypted_payment_id8
+ " (value incorrect if you are not the recipient of the tx)</h5>"
}
}
$("#decode-prove-results").html(decoding_results_str);
}
</script>
{{/enable_js}}
{{#has_inputs}}
{{#enable_mixins_details}}
@ -556,18 +300,4 @@
{{/with_ring_signatures}}
{{/have_raw_tx}}
{{#show_cache_times}}
<div class="center">
{{#construction_time}}
<h6 style="margin-top: 1px;color:#949490">
Tx details construction time: {{construction_time}} s
{{#from_cache}}
<br/>Tx read from the tx cache
{{/from_cache}}
</h6>
{{/construction_time}}
</div>
{{/show_cache_times}}
</div>

View file

@ -0,0 +1,71 @@
<div>
<H4>Block hash (height): {{blk_hash}} ({{blk_height}})</H4>
<h4>
Eight RandomX and correspoding assembly x86 programs used
to calcualte the PoW hash of the block.<br/>
The RandomX programs are executed on RandomX virtual machine.
</h4>
<h5>
Values of the integer and floating point registers
are also provided.
</h5>
{{#rx_codes}}
<h3> Program #{{rx_code_idx}}</h3>
<table class="center" style="width: 60%; margin-top:10px">
{{#first_program}}
<tr>
<td colspan="2">
Integer registers R:<br/><br/>
r0: 0x0000000000000000, r1: 0x0000000000000000, r2: 0x0000000000000000, r3: 0x0000000000000000<br/>
r4: 0x0000000000000000, r5: 0x0000000000000000, r6: 0x0000000000000000, r7: 0x0000000000000000<br/><br/>
Floating point registers F {lo, hi}:<br/><br/>
Initial values not accessible<br/><br/>
Floating point registers E {lo, hi}:<br/><br/>
Initial values not accessible<br/><br/>
Floating point registers A {lo, hi}:<br/><br/>
a0: {{a0}}, a1: {{a1}}<br/>
a2: {{a2}}, a3: {{a3}}<br/><br/>
{{/first_program}}
</td>
</tr>
<tr>
<td style="text-align: left;">RandomX code</td>
<td style="text-align: left;">ASM x86</td>
</tr>
<tr>
<td style="text-align: left;vertical-align: top;">
<pre>{{rx_code}}</pre>
</td>
<td style="text-align: left;vertical-align: top;">
<pre>{{rx_code_asm}}</pre>
</td>
</tr>
<tr>
<td colspan="2">
Integer registers R:<br/><br/>
r0: {{r0}}, r1: {{r1}}, r2: {{r2}}, r3: {{r3}}<br/>
r4: {{r4}}, r5: {{r5}}, r6: {{r6}}, r7: {{r7}}<br/><br/>
Floating point registers F {lo, hi}:<br/><br/>
f0: {{f0}}, f1: {{f1}}<br/>
f2: {{f2}}, f3: {{f3}}<br/><br/>
Floating point registers E {lo, hi}:<br/><br/>
e0: {{e0}}, e1: {{e1}}<br/>
e2: {{e2}}, e3: {{e3}}<br/><br/>
Floating point registers A {lo, hi}:<br/><br/>
a0: {{a0}}, a1: {{a1}}<br/>
a2: {{a2}}, a3: {{a3}}<br/><br/>
<br/>
</td>
</tr>
</table>
{{/rx_codes}}
</div>

View file

@ -1,4 +1,15 @@
<div class="center">
<h3 style="font-size: 12px; margin-top: 20px">
{{#refresh}}
<a href="/tx/{{tx_hash}}">Autorefresh is ON (10 s)</a>
{{/refresh}}
{{^refresh}}
<a href="/tx/{{tx_hash}}/autorefresh">Autorefresh is OFF</a>
{{/refresh}}
</h3>
</div>
<div>
{{#has_error}}

View file

@ -1272,4 +1272,31 @@ tx_to_hex(transaction const& tx)
return epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx));
}
void get_metric_prefix(cryptonote::difficulty_type hr, double& hr_d, char& prefix)
{
if (hr < 1000)
{
prefix = 0;
return;
}
static const char metric_prefixes[4] = { 'k', 'M', 'G', 'T' };
for (size_t i = 0; i < sizeof(metric_prefixes); ++i)
{
if (hr < 1000000)
{
hr_d = hr.convert_to<double>() / 1000;
prefix = metric_prefixes[i];
return;
}
hr /= 1000;
}
prefix = 0;
}
cryptonote::difficulty_type
make_difficulty(uint64_t low, uint64_t high)
{
return (cryptonote::difficulty_type(high) << 64) + low;
}
}

View file

@ -373,6 +373,12 @@ pause_execution(uint64_t no_seconds, const string& text = "now");
string
tx_to_hex(transaction const& tx);
void
get_metric_prefix(cryptonote::difficulty_type hr, double& hr_d, char& prefix);
cryptonote::difficulty_type
make_difficulty(uint64_t low, uint64_t high);
}
#endif //XMREG01_TOOLS_H