Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .env
Empty file.
39 changes: 39 additions & 0 deletions .github/workflows/cmake-single-platform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
name: CMake on a single platform

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release

jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}

- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ octra_wallet.exe
data/
*.oct
pvac/build/
.DS_Store
.DS_Store.env
44 changes: 42 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ else ifneq ($(IS_WIN),)
SHARED_EXT:=a
SHARED_FLAGS:=
SSL_PREFIX:=$(shell echo $$MINGW_PREFIX)
LDB_PREFIX:=$(shell echo $$MINGW_PREFIX)
CXXFLAGS+=-I$(SSL_PREFIX)/include -DCPPHTTPLIB_OPENSSL_SUPPORT
LDFLAGS:=-static -L$(SSL_PREFIX)/lib -L$(PVAC_BUILD) -lpvac -lleveldb -lssl -lcrypto -lws2_32 -lbcrypt -lcrypt32 -lgdi32 -lz
TARGET:=octra_wallet.exe
Expand All @@ -72,7 +73,46 @@ endif
CXXFLAGS+=-I$(PVAC_DIR)
LIBPVAC:=$(PVAC_BUILD)/libpvac.$(SHARED_EXT)

all: $(TARGET)
all: check-deps $(TARGET)

LEVELDB_PATHS:=/usr/include/leveldb/db.h /usr/local/include/leveldb/db.h /opt/homebrew/include/leveldb/db.h /opt/local/include/leveldb/db.h /mingw64/include/leveldb/db.h /ucrt64/include/leveldb/db.h /clang64/include/leveldb/db.h $(LDB_PREFIX)/include/leveldb/db.h
OPENSSL_PATHS:=/usr/include/openssl/evp.h /usr/local/include/openssl/evp.h /opt/homebrew/include/openssl/evp.h /opt/local/include/openssl/evp.h /mingw64/include/openssl/evp.h /ucrt64/include/openssl/evp.h /clang64/include/openssl/evp.h $(SSL_PREFIX)/include/openssl/evp.h

HAVE_LEVELDB:=$(shell for p in $(LEVELDB_PATHS); do [ -f "$$p" ] && { echo yes; exit 0; }; done; echo no)
HAVE_OPENSSL:=$(shell for p in $(OPENSSL_PATHS); do [ -f "$$p" ] && { echo yes; exit 0; }; done; echo no)

check-deps:
ifeq ($(OCTRA_SKIP_AUTOSETUP),)
ifeq ($(HAVE_LEVELDB)$(HAVE_OPENSSL),yesyes)
@true
else
@echo 'missing dependencies (leveldb=$(HAVE_LEVELDB) openssl=$(HAVE_OPENSSL))'
@echo 'running ./setup.sh --deps-only to install...'
@echo ''
@if [ -x ./setup.sh ]; then \
./setup.sh --deps-only || { \
echo ''; \
echo 'auto-install failed. install manually:'; \
echo 'sudo apt install libleveldb-dev libssl-dev (debian/ubuntu)'; \
echo 'brew install leveldb openssl@3 (macos)'; \
echo 'setup.bat from cmd.exe (windows)'; \
exit 1; \
}; \
else \
echo 'setup.sh not found. install manually:'; \
echo 'sudo apt install libleveldb-dev libssl-dev (debian/ubuntu)'; \
echo 'brew install leveldb openssl@3 (macos)'; \
echo 'setup.bat from cmd.exe (windows)'; \
exit 1; \
fi
@ok=no; for p in $(LEVELDB_PATHS); do [ -f "$$p" ] && ok=yes; done; \
[ "$$ok" = "yes" ] || { echo 'error: leveldb still missing. on windows run setup.bat from cmd.exe'; exit 1; }
@ok=no; for p in $(OPENSSL_PATHS); do [ -f "$$p" ] && ok=yes; done; \
[ "$$ok" = "yes" ] || { echo 'error: openssl still missing. on windows run setup.bat from cmd.exe'; exit 1; }
endif
else
@true
endif

$(PVAC_BUILD):
@mkdir -p $(PVAC_BUILD)
Expand Down Expand Up @@ -104,4 +144,4 @@ clean:
run: $(TARGET)
./$(TARGET) 8420

.PHONY: all clean run
.PHONY: all clean run check-deps
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# octra wallet (webcli)
![Version](https://img.shields.io/badge/version-0.04.10--alpha-blue)
![Version](https://img.shields.io/badge/version-0.05.01--alpha-blue)


a full-fledged web client based on a local server for working with the octra network (compatible with both **DEVNET** and **MAINNET ALPHA**).
Expand Down
77 changes: 72 additions & 5 deletions crypto_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#endif
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/bn.h>

extern "C" {
#include "lib/tweetnacl.h"
Expand Down Expand Up @@ -98,7 +99,7 @@ static const uint32_t K[64] = {
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

} // namespace detail
}

inline std::array<uint8_t, 32> sha256(const uint8_t* data, size_t len) {
using namespace detail;
Expand Down Expand Up @@ -147,7 +148,7 @@ inline std::array<uint8_t, 32> sha256(const uint8_t* data, size_t len) {

std::array<uint8_t, 32> out;
for (int i = 0; i < 8; i++) {
out[i * 4] = (uint8_t)(h[i] >> 24);
out[i * 4] = (uint8_t)(h[i] >> 24);
out[i * 4 + 1] = (uint8_t)(h[i] >> 16);
out[i * 4 + 2] = (uint8_t)(h[i] >> 8);
out[i * 4 + 3] = (uint8_t)(h[i]);
Expand Down Expand Up @@ -266,6 +267,52 @@ inline void ed25519_pk_to_curve25519(const uint8_t ed_sk[64], uint8_t x_pk[32])
crypto_scalarmult_base(x_pk, x_sk);
}

inline bool ed25519_pub_to_x25519(const uint8_t ed_pub[32], uint8_t x_pub[32]) {
BN_CTX* ctx = BN_CTX_new();
BIGNUM *p = BN_new(), *y = BN_new(), *one = BN_new();
BIGNUM *one_plus_y = BN_new(), *one_minus_y = BN_new();
BIGNUM *u = BN_new(), *inv = BN_new(), *p_minus_2 = BN_new();
bool ok = false;
if (!ctx || !p || !y || !one || !one_plus_y || !one_minus_y || !u || !inv || !p_minus_2) goto done;

if (!BN_set_bit(p, 255)) goto done;
if (!BN_sub_word(p, 19)) goto done;
BN_one(one);

{
uint8_t y_be[32];
for (int i = 0; i < 32; ++i) y_be[i] = ed_pub[31 - i];
y_be[0] &= 0x7F;
if (!BN_bin2bn(y_be, 32, y)) goto done;
}

if (!BN_mod_add(one_plus_y, one, y, p, ctx)) goto done;
if (!BN_mod_sub(one_minus_y, one, y, p, ctx)) goto done;
if (!BN_copy(p_minus_2, p)) goto done;
if (!BN_sub_word(p_minus_2, 2)) goto done;
if (!BN_mod_exp(inv, one_minus_y, p_minus_2, p, ctx)) goto done;
if (!BN_mod_mul(u, one_plus_y, inv, p, ctx)) goto done;

{
uint8_t u_be[32] = {0};
if (BN_bn2binpad(u, u_be, 32) != 32) goto done;
for (int i = 0; i < 32; ++i) x_pub[i] = u_be[31 - i];
}
ok = true;

done:
BN_free(p_minus_2);
BN_free(inv);
BN_free(u);
BN_free(one_minus_y);
BN_free(one_plus_y);
BN_free(one);
BN_free(y);
BN_free(p);
BN_CTX_free(ctx);
return ok;
}

inline void secure_zero(void* ptr, size_t len) {
volatile uint8_t* p = static_cast<volatile uint8_t*>(ptr);
while (len--) *p++ = 0;
Expand All @@ -285,6 +332,26 @@ inline void keypair_from_seed(const uint8_t seed[32], uint8_t sk[64], uint8_t pk
crypto_sign_seed_keypair(pk, sk, seed);
}

inline std::string validate_pin(const std::string& pin) {
if (pin.empty()) return "PIN required";
if (pin.size() < 8) return "PIN must be at least 8 characters";
if (pin.size() > 64) return "PIN too long (max 64 characters)";
if (pin.size() < 15) {
bool has_letter = false;
bool has_digit = false;
bool has_symbol = false;
for (unsigned char c : pin) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) has_letter = true;
else if (c >= '0' && c <= '9') has_digit = true;
else has_symbol = true;
}
if (!has_letter || !has_digit || !has_symbol) {
return "under 15 chars: must include a letter, a digit and a special symbol";
}
}
return "";
}

inline std::array<uint8_t, 32> derive_key_from_pin(
const std::string& pin, const uint8_t salt[32], int iterations = 600000) {
std::array<uint8_t, 32> key;
Expand Down Expand Up @@ -401,7 +468,7 @@ inline std::string generate_mnemonic_12() {
uint8_t entropy[16];
randombytes(entropy, 16);
auto hash = sha256(entropy, 16);
uint8_t bits[17]; // 128 + 8 = 136 bits available
uint8_t bits[17];
memcpy(bits, entropy, 16);
bits[16] = hash[0];
secure_zero(entropy, 16);
Expand Down Expand Up @@ -449,7 +516,7 @@ inline bool validate_mnemonic(const std::string& mnemonic) {
inline bool looks_like_mnemonic(const std::string& input) {
int spaces = 0;
for (char c : input) if (c == ' ') spaces++;
return spaces >= 11; // at least 12 words
return spaces >= 11;
}

} // namespace octra
}
Loading