Completed refactoring to separate nip files, and updating build.sh
This commit is contained in:
parent
8ed9262c65
commit
c3a9482882
|
@ -2,8 +2,6 @@ This library is fully staticly linked. There should be no external dependencies.
|
||||||
|
|
||||||
When building, use build.sh, not make.
|
When building, use build.sh, not make.
|
||||||
|
|
||||||
Use it as follows: build.sh -m "useful comment on changes being made"
|
|
||||||
|
|
||||||
When making TUI menus, try to use the first leter of the command and the key to press to execute that command. For example, if the command is "Open file" try to use a keypress of "o" upper or lower case to signal to open the file. Use this instead of number keyed menus when possible. In the command, the letter should be underlined that signifies the command.
|
When making TUI menus, try to use the first leter of the command and the key to press to execute that command. For example, if the command is "Open file" try to use a keypress of "o" upper or lower case to signal to open the file. Use this instead of number keyed menus when possible. In the command, the letter should be underlined that signifies the command.
|
||||||
|
|
||||||
When deleting, everything gets moved to the Trash folder.
|
When deleting, everything gets moved to the Trash folder.
|
||||||
|
|
187
CMakeLists.txt
187
CMakeLists.txt
|
@ -1,187 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.12)
|
|
||||||
project(nostr_core VERSION 1.0.0 LANGUAGES C)
|
|
||||||
|
|
||||||
# Set C standard
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
# Build options
|
|
||||||
option(NOSTR_BUILD_STATIC "Build static library" ON)
|
|
||||||
option(NOSTR_BUILD_SHARED "Build shared library" ON)
|
|
||||||
option(NOSTR_BUILD_EXAMPLES "Build examples" ON)
|
|
||||||
option(NOSTR_BUILD_TESTS "Build tests" ON)
|
|
||||||
option(NOSTR_ENABLE_WEBSOCKETS "Enable WebSocket support" ON)
|
|
||||||
option(NOSTR_USE_MBEDTLS "Use mbedTLS for crypto (otherwise use built-in)" OFF)
|
|
||||||
|
|
||||||
# Compiler flags
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror")
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "-g -O0")
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Include directories
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/cjson)
|
|
||||||
|
|
||||||
# Source files
|
|
||||||
set(NOSTR_CORE_SOURCES
|
|
||||||
nostr_core/core.c
|
|
||||||
nostr_core/core_relays.c
|
|
||||||
nostr_core/core_relay_pool.c
|
|
||||||
nostr_core/nostr_crypto.c
|
|
||||||
nostr_core/nostr_secp256k1.c
|
|
||||||
cjson/cJSON.c
|
|
||||||
)
|
|
||||||
|
|
||||||
set(NOSTR_CORE_HEADERS
|
|
||||||
nostr_core.h
|
|
||||||
nostr_crypto.h
|
|
||||||
cjson/cJSON.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add mbedTLS if enabled
|
|
||||||
if(NOSTR_USE_MBEDTLS)
|
|
||||||
add_subdirectory(mbedtls)
|
|
||||||
list(APPEND NOSTR_CORE_SOURCES mbedtls_wrapper.c)
|
|
||||||
add_definitions(-DNOSTR_USE_MBEDTLS=1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add WebSocket support if enabled
|
|
||||||
if(NOSTR_ENABLE_WEBSOCKETS)
|
|
||||||
file(GLOB WEBSOCKET_SOURCES "nostr_websocket/*.c")
|
|
||||||
file(GLOB WEBSOCKET_HEADERS "nostr_websocket/*.h")
|
|
||||||
list(APPEND NOSTR_CORE_SOURCES ${WEBSOCKET_SOURCES})
|
|
||||||
list(APPEND NOSTR_CORE_HEADERS ${WEBSOCKET_HEADERS})
|
|
||||||
add_definitions(-DNOSTR_ENABLE_WEBSOCKETS=1)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Create static library
|
|
||||||
if(NOSTR_BUILD_STATIC)
|
|
||||||
add_library(nostr_core_static STATIC ${NOSTR_CORE_SOURCES})
|
|
||||||
set_target_properties(nostr_core_static PROPERTIES OUTPUT_NAME nostr_core)
|
|
||||||
target_link_libraries(nostr_core_static m)
|
|
||||||
|
|
||||||
if(NOSTR_USE_MBEDTLS)
|
|
||||||
target_link_libraries(nostr_core_static mbedcrypto mbedx509 mbedtls)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Create shared library
|
|
||||||
if(NOSTR_BUILD_SHARED)
|
|
||||||
add_library(nostr_core_shared SHARED ${NOSTR_CORE_SOURCES})
|
|
||||||
set_target_properties(nostr_core_shared PROPERTIES OUTPUT_NAME nostr_core)
|
|
||||||
target_link_libraries(nostr_core_shared m)
|
|
||||||
|
|
||||||
if(NOSTR_USE_MBEDTLS)
|
|
||||||
target_link_libraries(nostr_core_shared mbedcrypto mbedx509 mbedtls)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set version information
|
|
||||||
set_target_properties(nostr_core_shared PROPERTIES
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
SOVERSION 1
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Create alias targets for easier integration
|
|
||||||
if(NOSTR_BUILD_STATIC)
|
|
||||||
add_library(nostr_core::static ALIAS nostr_core_static)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOSTR_BUILD_SHARED)
|
|
||||||
add_library(nostr_core::shared ALIAS nostr_core_shared)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Examples
|
|
||||||
if(NOSTR_BUILD_EXAMPLES)
|
|
||||||
add_subdirectory(examples)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Tests
|
|
||||||
if(NOSTR_BUILD_TESTS)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(tests)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
|
|
||||||
# Install libraries
|
|
||||||
if(NOSTR_BUILD_STATIC)
|
|
||||||
install(TARGETS nostr_core_static
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOSTR_BUILD_SHARED)
|
|
||||||
install(TARGETS nostr_core_shared
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Install headers
|
|
||||||
install(FILES ${NOSTR_CORE_HEADERS}
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nostr
|
|
||||||
)
|
|
||||||
|
|
||||||
# Install pkg-config file
|
|
||||||
configure_file(nostr_core.pc.in nostr_core.pc @ONLY)
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/nostr_core.pc
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate export configuration
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
|
|
||||||
configure_package_config_file(
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/nostr_core-config.cmake.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/nostr_core-config.cmake
|
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nostr_core
|
|
||||||
)
|
|
||||||
|
|
||||||
write_basic_package_version_file(
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/nostr_core-config-version.cmake
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
COMPATIBILITY SameMajorVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/nostr_core-config.cmake
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/nostr_core-config-version.cmake
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nostr_core
|
|
||||||
)
|
|
||||||
|
|
||||||
# Export targets
|
|
||||||
if(NOSTR_BUILD_STATIC OR NOSTR_BUILD_SHARED)
|
|
||||||
set(EXPORT_TARGETS "")
|
|
||||||
if(NOSTR_BUILD_STATIC)
|
|
||||||
list(APPEND EXPORT_TARGETS nostr_core_static)
|
|
||||||
endif()
|
|
||||||
if(NOSTR_BUILD_SHARED)
|
|
||||||
list(APPEND EXPORT_TARGETS nostr_core_shared)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(EXPORT nostr_core-targets
|
|
||||||
FILE nostr_core-targets.cmake
|
|
||||||
NAMESPACE nostr_core::
|
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nostr_core
|
|
||||||
)
|
|
||||||
|
|
||||||
export(TARGETS ${EXPORT_TARGETS}
|
|
||||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/nostr_core-targets.cmake
|
|
||||||
NAMESPACE nostr_core::
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Summary
|
|
||||||
message(STATUS "NOSTR Core Library Configuration:")
|
|
||||||
message(STATUS " Version: ${PROJECT_VERSION}")
|
|
||||||
message(STATUS " Build static library: ${NOSTR_BUILD_STATIC}")
|
|
||||||
message(STATUS " Build shared library: ${NOSTR_BUILD_SHARED}")
|
|
||||||
message(STATUS " Build examples: ${NOSTR_BUILD_EXAMPLES}")
|
|
||||||
message(STATUS " Build tests: ${NOSTR_BUILD_TESTS}")
|
|
||||||
message(STATUS " Enable WebSockets: ${NOSTR_ENABLE_WEBSOCKETS}")
|
|
||||||
message(STATUS " Use mbedTLS: ${NOSTR_USE_MBEDTLS}")
|
|
||||||
message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}")
|
|
495
Makefile
495
Makefile
|
@ -1,495 +0,0 @@
|
||||||
# NOSTR Core Library Makefile
|
|
||||||
# Standalone library build system
|
|
||||||
|
|
||||||
CC = gcc
|
|
||||||
AR = ar
|
|
||||||
CFLAGS = -Wall -Wextra -std=c99 -fPIC -O2
|
|
||||||
DEBUG_CFLAGS = -Wall -Wextra -std=c99 -fPIC -g -DDEBUG
|
|
||||||
STATIC_CFLAGS = -Wall -Wextra -std=c99 -O2 -static
|
|
||||||
|
|
||||||
# Logging compile flags
|
|
||||||
LOGGING_FLAGS ?= -DENABLE_FILE_LOGGING -DENABLE_WEBSOCKET_LOGGING -DENABLE_DEBUG_LOGGING
|
|
||||||
ifneq ($(ENABLE_LOGGING),)
|
|
||||||
LOGGING_FLAGS += -DENABLE_FILE_LOGGING -DENABLE_WEBSOCKET_LOGGING -DENABLE_DEBUG_LOGGING
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Include paths
|
|
||||||
INCLUDES = -I. -Inostr_core -Inostr_core/crypto -Icjson -Isecp256k1/include -Inostr_websocket -I./openssl-install/include
|
|
||||||
|
|
||||||
# Library source files - modular NIP-based structure
|
|
||||||
LIB_SOURCES = nostr_core/crypto/nostr_crypto.c nostr_core/crypto/nostr_secp256k1.c nostr_core/crypto/nostr_aes.c nostr_core/crypto/nostr_chacha20.c cjson/cJSON.c nostr_core/utils.c nostr_core/nip001.c nostr_core/nip005.c nostr_core/nip006.c nostr_core/nip011.c nostr_core/nip013.c nostr_core/nip019.c
|
|
||||||
LIB_OBJECTS = $(LIB_SOURCES:.c=.o)
|
|
||||||
ARM64_LIB_OBJECTS = $(LIB_SOURCES:.c=.arm64.o)
|
|
||||||
|
|
||||||
# secp256k1 library paths
|
|
||||||
SECP256K1_LIB = ./secp256k1/.libs/libsecp256k1.a
|
|
||||||
SECP256K1_PRECOMPUTED_LIB = ./secp256k1/.libs/libsecp256k1_precomputed.a
|
|
||||||
|
|
||||||
# ARM64 secp256k1 library paths
|
|
||||||
SECP256K1_ARM64_LIB = ./secp256k1/.libs/libsecp256k1_arm64.a
|
|
||||||
SECP256K1_ARM64_PRECOMPUTED_LIB = ./secp256k1/.libs/libsecp256k1_precomputed_arm64.a
|
|
||||||
|
|
||||||
# OpenSSL library paths
|
|
||||||
OPENSSL_LIB_SSL = ./openssl-install/lib64/libssl.a
|
|
||||||
OPENSSL_LIB_CRYPTO = ./openssl-install/lib64/libcrypto.a
|
|
||||||
|
|
||||||
# curl library paths
|
|
||||||
CURL_LIB = ./curl-install/lib/libcurl.a
|
|
||||||
|
|
||||||
# Library outputs (static only)
|
|
||||||
STATIC_LIB = libnostr_core.a
|
|
||||||
ARM64_STATIC_LIB = libnostr_core_arm64.a
|
|
||||||
|
|
||||||
# Example files
|
|
||||||
EXAMPLE_SOURCES = $(wildcard examples/*.c)
|
|
||||||
EXAMPLE_TARGETS = $(EXAMPLE_SOURCES:.c=)
|
|
||||||
|
|
||||||
# Default target - build both x64 and ARM64 static libraries
|
|
||||||
default: $(STATIC_LIB) $(ARM64_STATIC_LIB)
|
|
||||||
|
|
||||||
# Build all targets (static only)
|
|
||||||
all: $(STATIC_LIB) $(ARM64_STATIC_LIB) examples
|
|
||||||
|
|
||||||
# Build secp256k1 for x86_64
|
|
||||||
$(SECP256K1_LIB): secp256k1/configure
|
|
||||||
@echo "Building secp256k1 for x86_64..."
|
|
||||||
@cd secp256k1 && \
|
|
||||||
if [ ! -f .libs/libsecp256k1.a ]; then \
|
|
||||||
echo "Cleaning and configuring secp256k1..."; \
|
|
||||||
make distclean >/dev/null 2>&1 || true; \
|
|
||||||
./configure --enable-module-schnorrsig --enable-module-ecdh --enable-experimental --disable-shared --enable-static --with-pic; \
|
|
||||||
echo "Building secp256k1 library..."; \
|
|
||||||
make -j$(shell nproc 2>/dev/null || echo 4); \
|
|
||||||
else \
|
|
||||||
echo "secp256k1 library already exists, skipping build"; \
|
|
||||||
fi
|
|
||||||
@echo "x86_64 secp256k1 library built successfully"
|
|
||||||
|
|
||||||
# Build OpenSSL for x86_64 (minimal build optimized for curl)
|
|
||||||
$(OPENSSL_LIB_SSL) $(OPENSSL_LIB_CRYPTO): openssl-3.4.2/Configure
|
|
||||||
@echo "Building minimal OpenSSL for x86_64 (optimized for curl)..."
|
|
||||||
@cd openssl-3.4.2 && \
|
|
||||||
if [ ! -f ../openssl-install/lib64/libssl.a ] || [ ! -f ../openssl-install/lib64/libcrypto.a ]; then \
|
|
||||||
echo "Configuring minimal OpenSSL..."; \
|
|
||||||
make distclean >/dev/null 2>&1 || true; \
|
|
||||||
./Configure linux-x86_64 \
|
|
||||||
--prefix=$(PWD)/openssl-install \
|
|
||||||
--openssldir=$(PWD)/openssl-install/ssl \
|
|
||||||
no-shared no-dso no-apps no-docs \
|
|
||||||
no-ssl3 no-tls1 no-tls1_1 \
|
|
||||||
no-engine no-comp no-legacy \
|
|
||||||
no-gost no-idea no-seed no-md2 no-md4 \
|
|
||||||
no-mdc2 no-rmd160 no-camellia no-rc5 \
|
|
||||||
no-bf no-cast no-des \
|
|
||||||
enable-tls1_2 enable-tls1_3; \
|
|
||||||
echo "Building minimal OpenSSL libraries..."; \
|
|
||||||
make -j$(shell nproc 2>/dev/null || echo 4); \
|
|
||||||
make install_sw >/dev/null 2>&1; \
|
|
||||||
else \
|
|
||||||
echo "OpenSSL libraries already exist, skipping build"; \
|
|
||||||
fi
|
|
||||||
@echo "x86_64 minimal OpenSSL libraries built successfully"
|
|
||||||
|
|
||||||
# Build curl for x86_64 (minimal HTTPS-only build)
|
|
||||||
$(CURL_LIB): curl-8.15.0/curl-8.15.0/configure $(OPENSSL_LIB_SSL)
|
|
||||||
@echo "Building minimal curl for x86_64 (HTTPS-only)..."
|
|
||||||
@cd curl-8.15.0/curl-8.15.0 && \
|
|
||||||
if [ ! -f ../../curl-install/lib/libcurl.a ]; then \
|
|
||||||
echo "Configuring minimal curl..."; \
|
|
||||||
make distclean >/dev/null 2>&1 || true; \
|
|
||||||
./configure --prefix=$(PWD)/curl-install \
|
|
||||||
--with-openssl=$(PWD)/openssl-install \
|
|
||||||
--disable-shared --enable-static \
|
|
||||||
--disable-ftp --disable-file --disable-ldap --disable-ldaps \
|
|
||||||
--disable-pop3 --disable-imap --disable-smtp \
|
|
||||||
--disable-gopher --disable-smb --disable-telnet \
|
|
||||||
--disable-tftp --disable-dict --disable-rtsp \
|
|
||||||
--disable-manual --disable-libcurl-option \
|
|
||||||
--without-libpsl --without-nghttp2 --without-brotli --without-zstd \
|
|
||||||
--without-libidn2 --without-librtmp --without-libssh2; \
|
|
||||||
echo "Building minimal curl library..."; \
|
|
||||||
make -j$(shell nproc 2>/dev/null || echo 4); \
|
|
||||||
make install >/dev/null 2>&1; \
|
|
||||||
else \
|
|
||||||
echo "curl library already exists, skipping build"; \
|
|
||||||
fi
|
|
||||||
@echo "x86_64 minimal curl library built successfully"
|
|
||||||
|
|
||||||
# Static library - includes secp256k1 and OpenSSL objects for self-contained library
|
|
||||||
$(STATIC_LIB): $(LIB_OBJECTS) $(SECP256K1_LIB) $(OPENSSL_LIB_SSL) $(OPENSSL_LIB_CRYPTO)
|
|
||||||
@echo "Creating self-contained static library: $@"
|
|
||||||
@echo "Extracting secp256k1 objects..."
|
|
||||||
@mkdir -p .tmp_secp256k1
|
|
||||||
@cd .tmp_secp256k1 && $(AR) x ../$(SECP256K1_LIB)
|
|
||||||
@if [ -f $(SECP256K1_PRECOMPUTED_LIB) ]; then \
|
|
||||||
echo "Extracting secp256k1_precomputed objects..."; \
|
|
||||||
cd .tmp_secp256k1 && $(AR) x ../$(SECP256K1_PRECOMPUTED_LIB); \
|
|
||||||
fi
|
|
||||||
@echo "Extracting OpenSSL objects..."
|
|
||||||
@mkdir -p .tmp_openssl
|
|
||||||
@cd .tmp_openssl && $(AR) x ../$(OPENSSL_LIB_SSL)
|
|
||||||
@cd .tmp_openssl && $(AR) x ../$(OPENSSL_LIB_CRYPTO)
|
|
||||||
@echo "Combining all objects into $@..."
|
|
||||||
$(AR) rcs $@ $(LIB_OBJECTS) .tmp_secp256k1/*.o .tmp_openssl/*.o
|
|
||||||
@rm -rf .tmp_secp256k1 .tmp_openssl
|
|
||||||
@echo "Self-contained static library created: $@"
|
|
||||||
|
|
||||||
# ARM64 cross-compilation settings
|
|
||||||
ARM64_CC = aarch64-linux-gnu-gcc
|
|
||||||
ARM64_AR = aarch64-linux-gnu-ar
|
|
||||||
ARM64_INCLUDES = -I. -Inostr_core -Icjson -Isecp256k1/include -Inostr_websocket -I./openssl-install/include -I./curl-install/include
|
|
||||||
|
|
||||||
# ARM64 static library - includes secp256k1 objects for self-contained library (OpenSSL handled separately for cross-compile)
|
|
||||||
$(ARM64_STATIC_LIB): $(ARM64_LIB_OBJECTS) $(SECP256K1_ARM64_LIB)
|
|
||||||
@echo "Creating self-contained ARM64 static library: $@"
|
|
||||||
@echo "Extracting ARM64 secp256k1 objects..."
|
|
||||||
@mkdir -p .tmp_secp256k1_arm64
|
|
||||||
@cd .tmp_secp256k1_arm64 && $(ARM64_AR) x ../$(SECP256K1_ARM64_LIB)
|
|
||||||
@if [ -f $(SECP256K1_ARM64_PRECOMPUTED_LIB) ]; then \
|
|
||||||
echo "Extracting ARM64 secp256k1_precomputed objects..."; \
|
|
||||||
cd .tmp_secp256k1_arm64 && $(ARM64_AR) x ../$(SECP256K1_ARM64_PRECOMPUTED_LIB); \
|
|
||||||
fi
|
|
||||||
@echo "Note: ARM64 users need to link with OpenSSL separately: -lssl -lcrypto"
|
|
||||||
@echo "Combining all ARM64 objects into $@..."
|
|
||||||
$(ARM64_AR) rcs $@ $(ARM64_LIB_OBJECTS) .tmp_secp256k1_arm64/*.o
|
|
||||||
@rm -rf .tmp_secp256k1_arm64
|
|
||||||
@echo "Self-contained ARM64 static library created: $@"
|
|
||||||
|
|
||||||
# Build secp256k1 for ARM64
|
|
||||||
$(SECP256K1_ARM64_LIB): secp256k1/configure
|
|
||||||
@echo "Building secp256k1 for ARM64..."
|
|
||||||
@echo "Cleaning secp256k1 source directory first..."
|
|
||||||
@cd secp256k1 && make distclean 2>/dev/null || true
|
|
||||||
@mkdir -p secp256k1/build_arm64
|
|
||||||
@cd secp256k1/build_arm64 && \
|
|
||||||
CC=$(ARM64_CC) AR=$(ARM64_AR) \
|
|
||||||
../configure --host=aarch64-linux-gnu \
|
|
||||||
--enable-module-schnorrsig \
|
|
||||||
--enable-module-ecdh \
|
|
||||||
--enable-experimental \
|
|
||||||
--disable-shared \
|
|
||||||
--enable-static \
|
|
||||||
--with-pic \
|
|
||||||
--prefix=$(PWD)/secp256k1/install_arm64 && \
|
|
||||||
make -j$(shell nproc 2>/dev/null || echo 4)
|
|
||||||
@mkdir -p secp256k1/.libs
|
|
||||||
@cp secp256k1/build_arm64/.libs/libsecp256k1.a $(SECP256K1_ARM64_LIB)
|
|
||||||
@if [ -f secp256k1/build_arm64/.libs/libsecp256k1_precomputed.a ]; then \
|
|
||||||
cp secp256k1/build_arm64/.libs/libsecp256k1_precomputed.a $(SECP256K1_ARM64_PRECOMPUTED_LIB); \
|
|
||||||
fi
|
|
||||||
@echo "ARM64 secp256k1 libraries built successfully"
|
|
||||||
@echo "Restoring x64 secp256k1 build..."
|
|
||||||
@cd secp256k1 && ./configure --enable-module-schnorrsig --enable-module-ecdh --enable-experimental --disable-shared --enable-static --with-pic >/dev/null 2>&1 && make -j$(shell nproc 2>/dev/null || echo 4) >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
# Object files (x86_64)
|
|
||||||
%.o: %.c
|
|
||||||
@echo "Compiling: $<"
|
|
||||||
$(CC) $(CFLAGS) $(LOGGING_FLAGS) $(INCLUDES) -c $< -o $@
|
|
||||||
|
|
||||||
# ARM64 object files
|
|
||||||
%.arm64.o: %.c
|
|
||||||
@echo "Compiling for ARM64: $<"
|
|
||||||
$(ARM64_CC) $(CFLAGS) $(LOGGING_FLAGS) $(ARM64_INCLUDES) -c $< -o $@
|
|
||||||
|
|
||||||
# Examples
|
|
||||||
examples: $(EXAMPLE_TARGETS)
|
|
||||||
|
|
||||||
examples/%: examples/%.c $(STATIC_LIB)
|
|
||||||
@echo "Building example: $@"
|
|
||||||
$(CC) $(STATIC_CFLAGS) $(LOGGING_FLAGS) $(INCLUDES) $< -o $@ ./libnostr_core.a -lm
|
|
||||||
|
|
||||||
# Architecture-specific targets
|
|
||||||
x64: $(STATIC_LIB)
|
|
||||||
x64-only: $(STATIC_LIB)
|
|
||||||
|
|
||||||
# ARM64 targets
|
|
||||||
arm64: $(ARM64_STATIC_LIB)
|
|
||||||
arm64-all: $(ARM64_STATIC_LIB)
|
|
||||||
arm64-only: $(ARM64_STATIC_LIB)
|
|
||||||
|
|
||||||
# Debug build
|
|
||||||
debug: CFLAGS = $(DEBUG_CFLAGS)
|
|
||||||
debug: clean default
|
|
||||||
|
|
||||||
# Install library to system (static only)
|
|
||||||
install: $(STATIC_LIB)
|
|
||||||
@echo "Installing static library..."
|
|
||||||
sudo cp $(STATIC_LIB) /usr/local/lib/
|
|
||||||
sudo cp nostr_core/nostr_core.h /usr/local/include/
|
|
||||||
sudo cp nostr_core/nostr_crypto.h /usr/local/include/
|
|
||||||
|
|
||||||
# Uninstall library
|
|
||||||
uninstall:
|
|
||||||
@echo "Uninstalling library..."
|
|
||||||
sudo rm -f /usr/local/lib/$(STATIC_LIB)
|
|
||||||
sudo rm -f /usr/local/include/nostr_core.h
|
|
||||||
sudo rm -f /usr/local/include/nostr_crypto.h
|
|
||||||
|
|
||||||
# Test executables
|
|
||||||
CRYPTO_TEST_EXEC = tests/nostr_crypto_test
|
|
||||||
CORE_TEST_EXEC = tests/nostr_core_test
|
|
||||||
RELAY_POOL_TEST_EXEC = tests/relay_pool_test
|
|
||||||
EVENT_GEN_TEST_EXEC = tests/test_event_generation
|
|
||||||
POW_LOOP_TEST_EXEC = tests/test_pow_loop
|
|
||||||
NIP04_TEST_EXEC = tests/nip04_test
|
|
||||||
HTTP_TEST_EXEC = tests/http_test
|
|
||||||
WSS_TEST_EXEC = tests/wss_test
|
|
||||||
STATIC_LINKING_TEST_EXEC = tests/static_linking_only_test
|
|
||||||
MAKEFILE_STATIC_TEST_EXEC = tests/makefile_static_test
|
|
||||||
NIP05_TEST_EXEC = tests/nip05_test
|
|
||||||
NIP11_TEST_EXEC = tests/nip11_test
|
|
||||||
ARM64_CRYPTO_TEST_EXEC = tests/nostr_crypto_test_arm64
|
|
||||||
ARM64_CORE_TEST_EXEC = tests/nostr_core_test_arm64
|
|
||||||
ARM64_RELAY_POOL_TEST_EXEC = tests/relay_pool_test_arm64
|
|
||||||
ARM64_NIP04_TEST_EXEC = tests/nip04_test_arm64
|
|
||||||
|
|
||||||
# Test compilation flags - matches exact customer usage pattern
|
|
||||||
TEST_CFLAGS = -Wall -Wextra -std=c99 -g -I. -I./secp256k1/include -I./openssl-install/include
|
|
||||||
TEST_LDFLAGS = ./libnostr_core.a -lm -static
|
|
||||||
ARM64_TEST_CFLAGS = -Wall -Wextra -std=c99 -g -I.
|
|
||||||
ARM64_TEST_LDFLAGS = ./libnostr_core_arm64.a -lm -static
|
|
||||||
|
|
||||||
# Build crypto test executable (x86_64)
|
|
||||||
$(CRYPTO_TEST_EXEC): tests/nostr_crypto_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building crypto test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build core test executable (x86_64)
|
|
||||||
$(CORE_TEST_EXEC): tests/nostr_core_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building core test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build relay pool test executable (x86_64)
|
|
||||||
$(RELAY_POOL_TEST_EXEC): tests/relay_pool_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building relay pool test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build event generation test executable (x86_64)
|
|
||||||
$(EVENT_GEN_TEST_EXEC): tests/test_event_generation.c $(STATIC_LIB)
|
|
||||||
@echo "Building event generation test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build PoW loop test executable (x86_64)
|
|
||||||
$(POW_LOOP_TEST_EXEC): tests/test_pow_loop.c $(STATIC_LIB)
|
|
||||||
@echo "Building PoW loop test program (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build NIP-04 test executable (x86_64)
|
|
||||||
$(NIP04_TEST_EXEC): tests/nip04_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building NIP-04 encryption test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build HTTP test executable (x86_64) - Uses customer linking pattern
|
|
||||||
$(HTTP_TEST_EXEC): tests/http_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building HTTP/curl compatibility test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build WebSocket SSL test executable (x86_64)
|
|
||||||
$(WSS_TEST_EXEC): tests/wss_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building WebSocket SSL/OpenSSL compatibility test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build static linking test executable (x86_64)
|
|
||||||
$(STATIC_LINKING_TEST_EXEC): tests/static_linking_only_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building static linking verification test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build Makefile-based static test executable (x86_64) - No library dependency, just parses Makefile
|
|
||||||
$(MAKEFILE_STATIC_TEST_EXEC): tests/makefile_static_test.c
|
|
||||||
@echo "Building Makefile-based static configuration test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ -static
|
|
||||||
|
|
||||||
# Build NIP-05 test executable (x86_64) - Uses customer linking pattern
|
|
||||||
$(NIP05_TEST_EXEC): tests/nip05_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building NIP-05 identifier verification test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build NIP-11 test executable (x86_64) - Uses customer linking pattern
|
|
||||||
$(NIP11_TEST_EXEC): tests/nip11_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building NIP-11 relay information test (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build simple initialization test executable (x86_64)
|
|
||||||
tests/simple_init_test: tests/simple_init_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building simple initialization test program (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build ChaCha20 test executable (x86_64)
|
|
||||||
tests/chacha20_test: tests/chacha20_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building ChaCha20 RFC 8439 test suite (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build sync test executable (x86_64)
|
|
||||||
tests/sync_test: tests/sync_test.c $(STATIC_LIB)
|
|
||||||
@echo "Building synchronous relay query test program (x86_64)..."
|
|
||||||
$(CC) $(TEST_CFLAGS) $< -o $@ $(TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build crypto test ARM64 executable
|
|
||||||
$(ARM64_CRYPTO_TEST_EXEC): tests/nostr_crypto_test.c $(ARM64_STATIC_LIB)
|
|
||||||
@echo "Building crypto test suite (ARM64)..."
|
|
||||||
$(ARM64_CC) $(ARM64_TEST_CFLAGS) $< -o $@ $(ARM64_TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build core test ARM64 executable
|
|
||||||
$(ARM64_CORE_TEST_EXEC): tests/nostr_core_test.c $(ARM64_STATIC_LIB)
|
|
||||||
@echo "Building core test suite (ARM64)..."
|
|
||||||
$(ARM64_CC) $(ARM64_TEST_CFLAGS) $< -o $@ $(ARM64_TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build relay pool test ARM64 executable
|
|
||||||
$(ARM64_RELAY_POOL_TEST_EXEC): tests/relay_pool_test.c $(ARM64_STATIC_LIB)
|
|
||||||
@echo "Building relay pool test suite (ARM64)..."
|
|
||||||
$(ARM64_CC) $(ARM64_TEST_CFLAGS) $< -o $@ $(ARM64_TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Build NIP-04 test ARM64 executable
|
|
||||||
$(ARM64_NIP04_TEST_EXEC): tests/nip04_test.c $(ARM64_STATIC_LIB)
|
|
||||||
@echo "Building NIP-04 encryption test suite (ARM64)..."
|
|
||||||
$(ARM64_CC) $(ARM64_TEST_CFLAGS) $< -o $@ $(ARM64_TEST_LDFLAGS)
|
|
||||||
|
|
||||||
# Run crypto tests (x86_64)
|
|
||||||
test-crypto: $(CRYPTO_TEST_EXEC)
|
|
||||||
@echo "Running crypto tests (x86_64)..."
|
|
||||||
./$(CRYPTO_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run core tests (x86_64)
|
|
||||||
test-core: $(CORE_TEST_EXEC)
|
|
||||||
@echo "Running core tests (x86_64)..."
|
|
||||||
./$(CORE_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run relay pool tests (x86_64)
|
|
||||||
test-relay-pool: $(RELAY_POOL_TEST_EXEC)
|
|
||||||
@echo "Running relay pool tests (x86_64)..."
|
|
||||||
./$(RELAY_POOL_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run NIP-04 tests (x86_64)
|
|
||||||
test-nip04: $(NIP04_TEST_EXEC)
|
|
||||||
@echo "Running NIP-04 encryption tests (x86_64)..."
|
|
||||||
./$(NIP04_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run HTTP tests (x86_64)
|
|
||||||
test-http: $(HTTP_TEST_EXEC)
|
|
||||||
@echo "Running HTTP/curl compatibility tests (x86_64)..."
|
|
||||||
./$(HTTP_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run WebSocket SSL tests (x86_64)
|
|
||||||
test-wss: $(WSS_TEST_EXEC)
|
|
||||||
@echo "Running WebSocket SSL/OpenSSL compatibility tests (x86_64)..."
|
|
||||||
./$(WSS_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run static linking verification test (x86_64)
|
|
||||||
test-static-linking: $(STATIC_LINKING_TEST_EXEC)
|
|
||||||
@echo "Running static linking verification test (x86_64)..."
|
|
||||||
./$(STATIC_LINKING_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run Makefile-based static configuration test (x86_64)
|
|
||||||
test-makefile-static: $(MAKEFILE_STATIC_TEST_EXEC)
|
|
||||||
@echo "Running Makefile-based static configuration test (x86_64)..."
|
|
||||||
./$(MAKEFILE_STATIC_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run NIP-05 tests (x86_64)
|
|
||||||
test-nip05: $(NIP05_TEST_EXEC)
|
|
||||||
@echo "Running NIP-05 identifier verification tests (x86_64)..."
|
|
||||||
./$(NIP05_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run NIP-11 tests (x86_64)
|
|
||||||
test-nip11: $(NIP11_TEST_EXEC)
|
|
||||||
@echo "Running NIP-11 relay information tests (x86_64)..."
|
|
||||||
./$(NIP11_TEST_EXEC)
|
|
||||||
|
|
||||||
# Run all test suites (x86_64)
|
|
||||||
test: test-crypto test-core test-relay-pool test-nip04 test-http test-wss test-static-linking test-makefile-static test-nip05 test-nip11
|
|
||||||
|
|
||||||
# Run crypto tests ARM64 (requires qemu-user-static or ARM64 system)
|
|
||||||
test-crypto-arm64: $(ARM64_CRYPTO_TEST_EXEC)
|
|
||||||
@echo "Running crypto tests (ARM64)..."
|
|
||||||
@if command -v qemu-aarch64-static >/dev/null 2>&1; then \
|
|
||||||
echo "Using qemu-aarch64-static to run ARM64 binary..."; \
|
|
||||||
qemu-aarch64-static ./$(ARM64_CRYPTO_TEST_EXEC); \
|
|
||||||
else \
|
|
||||||
echo "qemu-aarch64-static not found. ARM64 binary built but cannot run on x86_64."; \
|
|
||||||
echo "To run: copy $(ARM64_CRYPTO_TEST_EXEC) to ARM64 system and execute."; \
|
|
||||||
file ./$(ARM64_CRYPTO_TEST_EXEC); \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run core tests ARM64 (requires qemu-user-static or ARM64 system)
|
|
||||||
test-core-arm64: $(ARM64_CORE_TEST_EXEC)
|
|
||||||
@echo "Running core tests (ARM64)..."
|
|
||||||
@if command -v qemu-aarch64-static >/dev/null 2>&1; then \
|
|
||||||
echo "Using qemu-aarch64-static to run ARM64 binary..."; \
|
|
||||||
qemu-aarch64-static ./$(ARM64_CORE_TEST_EXEC); \
|
|
||||||
else \
|
|
||||||
echo "qemu-aarch64-static not found. ARM64 binary built but cannot run on x86_64."; \
|
|
||||||
echo "To run: copy $(ARM64_CORE_TEST_EXEC) to ARM64 system and execute."; \
|
|
||||||
file ./$(ARM64_CORE_TEST_EXEC); \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run relay pool tests ARM64 (requires qemu-user-static or ARM64 system)
|
|
||||||
test-relay-pool-arm64: $(ARM64_RELAY_POOL_TEST_EXEC)
|
|
||||||
@echo "Running relay pool tests (ARM64)..."
|
|
||||||
@if command -v qemu-aarch64-static >/dev/null 2>&1; then \
|
|
||||||
echo "Using qemu-aarch64-static to run ARM64 binary..."; \
|
|
||||||
qemu-aarch64-static ./$(ARM64_RELAY_POOL_TEST_EXEC); \
|
|
||||||
else \
|
|
||||||
echo "qemu-aarch64-static not found. ARM64 binary built but cannot run on x86_64."; \
|
|
||||||
echo "To run: copy $(ARM64_RELAY_POOL_TEST_EXEC) to ARM64 system and execute."; \
|
|
||||||
file ./$(ARM64_RELAY_POOL_TEST_EXEC); \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run all test suites on ARM64
|
|
||||||
test-arm64: test-crypto-arm64 test-core-arm64 test-relay-pool-arm64
|
|
||||||
|
|
||||||
# Run tests on both architectures
|
|
||||||
test-all: test test-arm64
|
|
||||||
|
|
||||||
# Test the library with simple example
|
|
||||||
test-simple: examples/simple_keygen
|
|
||||||
@echo "Running simple key generation test..."
|
|
||||||
./examples/simple_keygen
|
|
||||||
|
|
||||||
# Clean build artifacts
|
|
||||||
clean:
|
|
||||||
@echo "Cleaning build artifacts..."
|
|
||||||
rm -f $(LIB_OBJECTS) $(ARM64_LIB_OBJECTS)
|
|
||||||
rm -f $(STATIC_LIB) $(ARM64_STATIC_LIB)
|
|
||||||
rm -f $(SECP256K1_ARM64_LIB) $(SECP256K1_ARM64_PRECOMPUTED_LIB)
|
|
||||||
rm -f $(EXAMPLE_TARGETS)
|
|
||||||
rm -rf .tmp_secp256k1 .tmp_secp256k1_arm64 .tmp_openssl
|
|
||||||
rm -rf secp256k1/build_arm64 secp256k1/install_arm64
|
|
||||||
|
|
||||||
# Create distribution package
|
|
||||||
dist: clean
|
|
||||||
@echo "Creating distribution package..."
|
|
||||||
mkdir -p dist/nostr_core
|
|
||||||
cp -r *.h *.c Makefile examples/ tests/ README.md LICENSE dist/nostr_core/ 2>/dev/null || true
|
|
||||||
cd dist && tar -czf nostr_core.tar.gz nostr_core/
|
|
||||||
@echo "Distribution package created: dist/nostr_core.tar.gz"
|
|
||||||
|
|
||||||
# Help
|
|
||||||
help:
|
|
||||||
@echo "NOSTR Core Library Build System"
|
|
||||||
@echo "==============================="
|
|
||||||
@echo ""
|
|
||||||
@echo "Available targets:"
|
|
||||||
@echo " default - Build both x64 and ARM64 static libraries (recommended)"
|
|
||||||
@echo " all - Build both architectures and examples"
|
|
||||||
@echo " x64 - Build x64 static library only"
|
|
||||||
@echo " x64-only - Build x64 static library only"
|
|
||||||
@echo " arm64 - Build ARM64 static library only"
|
|
||||||
@echo " arm64-only - Build ARM64 static library only"
|
|
||||||
@echo " arm64-all - Build ARM64 static library only"
|
|
||||||
@echo " debug - Build with debug symbols (both architectures)"
|
|
||||||
@echo " examples - Build example programs"
|
|
||||||
@echo " test - Run simple test"
|
|
||||||
@echo " test-crypto - Run comprehensive crypto test suite"
|
|
||||||
@echo " install - Install static library to system (/usr/local)"
|
|
||||||
@echo " uninstall - Remove library from system"
|
|
||||||
@echo " clean - Remove build artifacts"
|
|
||||||
@echo " dist - Create distribution package"
|
|
||||||
@echo " help - Show this help"
|
|
||||||
@echo ""
|
|
||||||
@echo "Library outputs (static only, self-contained):"
|
|
||||||
@echo " $(STATIC_LIB) - x86_64 static library (includes secp256k1 + OpenSSL)"
|
|
||||||
@echo " $(ARM64_STATIC_LIB) - ARM64 static library (includes secp256k1, needs OpenSSL)"
|
|
||||||
@echo ""
|
|
||||||
@echo "x64 library: Users only need to link with the library + -lm"
|
|
||||||
@echo "ARM64 library: Users need to link with the library + -lssl -lcrypto -lm"
|
|
||||||
|
|
||||||
.PHONY: default all x64 x64-only arm64 arm64-all arm64-only debug examples test test-crypto install uninstall clean dist help
|
|
169
build.sh
169
build.sh
|
@ -5,28 +5,51 @@
|
||||||
|
|
||||||
set -e # Exit on error
|
set -e # Exit on error
|
||||||
|
|
||||||
# Colors for output
|
# Color constants
|
||||||
RED='\033[0;31m'
|
RED='\033[31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[34m'
|
||||||
NC='\033[0m' # No Color
|
BOLD='\033[1m'
|
||||||
|
RESET='\033[0m'
|
||||||
|
|
||||||
# Function to print colored output
|
# Detect if we should use colors (terminal output and not piped)
|
||||||
|
USE_COLORS=true
|
||||||
|
if [ ! -t 1 ] || [ "$NO_COLOR" = "1" ]; then
|
||||||
|
USE_COLORS=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to print output with colors
|
||||||
print_info() {
|
print_info() {
|
||||||
echo -e "${BLUE}[INFO]${NC} $1"
|
if [ "$USE_COLORS" = true ]; then
|
||||||
|
echo -e "${BLUE}[INFO]${RESET} $1"
|
||||||
|
else
|
||||||
|
echo "[INFO] $1"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_success() {
|
print_success() {
|
||||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
if [ "$USE_COLORS" = true ]; then
|
||||||
|
echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} $1"
|
||||||
|
else
|
||||||
|
echo "[SUCCESS] $1"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_warning() {
|
print_warning() {
|
||||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
if [ "$USE_COLORS" = true ]; then
|
||||||
|
echo -e "${YELLOW}[WARNING]${RESET} $1"
|
||||||
|
else
|
||||||
|
echo "[WARNING] $1"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
echo -e "${RED}[ERROR]${NC} $1"
|
if [ "$USE_COLORS" = true ]; then
|
||||||
|
echo -e "${RED}${BOLD}[ERROR]${RESET} $1"
|
||||||
|
else
|
||||||
|
echo "[ERROR] $1"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Default values
|
# Default values
|
||||||
|
@ -35,6 +58,7 @@ FORCE_NIPS=""
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
HELP=false
|
HELP=false
|
||||||
BUILD_TESTS=false
|
BUILD_TESTS=false
|
||||||
|
NO_COLOR_FLAG=false
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
|
@ -55,10 +79,14 @@ while [[ $# -gt 0 ]]; do
|
||||||
VERBOSE=true
|
VERBOSE=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--tests)
|
--tests|-t)
|
||||||
BUILD_TESTS=true
|
BUILD_TESTS=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--no-color)
|
||||||
|
NO_COLOR_FLAG=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
--help|-h)
|
--help|-h)
|
||||||
HELP=true
|
HELP=true
|
||||||
shift
|
shift
|
||||||
|
@ -71,6 +99,11 @@ while [[ $# -gt 0 ]]; do
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Apply no-color flag
|
||||||
|
if [ "$NO_COLOR_FLAG" = true ]; then
|
||||||
|
USE_COLORS=false
|
||||||
|
fi
|
||||||
|
|
||||||
# Show help
|
# Show help
|
||||||
if [ "$HELP" = true ]; then
|
if [ "$HELP" = true ]; then
|
||||||
echo "NOSTR Core Library - Customer Build Script"
|
echo "NOSTR Core Library - Customer Build Script"
|
||||||
|
@ -85,8 +118,9 @@ if [ "$HELP" = true ]; then
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " --nips=1,5,6,19 Force specific NIPs (comma-separated)"
|
echo " --nips=1,5,6,19 Force specific NIPs (comma-separated)"
|
||||||
echo " --nips=all Include all available NIPs"
|
echo " --nips=all Include all available NIPs"
|
||||||
echo " --tests Build all test programs in tests/ directory"
|
echo " --tests, -t Build all test programs in tests/ directory"
|
||||||
echo " --verbose, -v Verbose output"
|
echo " --verbose, -v Verbose output"
|
||||||
|
echo " --no-color Disable colored output"
|
||||||
echo " --help, -h Show this help"
|
echo " --help, -h Show this help"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Auto-Detection:"
|
echo "Auto-Detection:"
|
||||||
|
@ -107,17 +141,25 @@ if [ "$HELP" = true ]; then
|
||||||
echo " $0 x64 # Auto-detect NIPs, build for x64"
|
echo " $0 x64 # Auto-detect NIPs, build for x64"
|
||||||
echo " $0 --nips=1,6,19 # Force NIPs 1,6,19 only"
|
echo " $0 --nips=1,6,19 # Force NIPs 1,6,19 only"
|
||||||
echo " $0 arm64 --nips=all # Build all NIPs for ARM64"
|
echo " $0 arm64 --nips=all # Build all NIPs for ARM64"
|
||||||
|
echo " $0 -t # Build library and all tests"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "NOSTR Core Library - Customer Build Script"
|
print_info "NOSTR Core Library - Customer Build Script"
|
||||||
print_info "Auto-detecting needed NIPs from your source code..."
|
print_info "Auto-detecting needed NIPs from your source code..."
|
||||||
|
|
||||||
# Detect NIPs from source files
|
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ AUTODETECT NIPS FROM SOURCE FILES
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
|
||||||
|
|
||||||
NEEDED_NIPS=""
|
NEEDED_NIPS=""
|
||||||
if [ -n "$FORCE_NIPS" ]; then
|
if [ -n "$FORCE_NIPS" ]; then
|
||||||
if [ "$FORCE_NIPS" = "all" ]; then
|
if [ "$FORCE_NIPS" = "all" ]; then
|
||||||
NEEDED_NIPS="001 005 006 011 013 019 044"
|
NEEDED_NIPS="001 004 005 006 011 013 019 044"
|
||||||
print_info "Forced: Building all available NIPs"
|
print_info "Forced: Building all available NIPs"
|
||||||
else
|
else
|
||||||
# Convert comma-separated list to space-separated with 3-digit format
|
# Convert comma-separated list to space-separated with 3-digit format
|
||||||
|
@ -152,12 +194,26 @@ else
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# If building tests, include all NIPs to ensure test compatibility
|
||||||
|
if [ "$BUILD_TESTS" = true ] && [ -z "$FORCE_NIPS" ]; then
|
||||||
|
NEEDED_NIPS="001 005 006 011 013 019 044"
|
||||||
|
print_info "Building tests - including all available NIPs for test compatibility"
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure NIP-001 is always included (required for core functionality)
|
# Ensure NIP-001 is always included (required for core functionality)
|
||||||
if ! echo "$NEEDED_NIPS" | grep -q "001"; then
|
if ! echo "$NEEDED_NIPS" | grep -q "001"; then
|
||||||
NEEDED_NIPS="001 $NEEDED_NIPS"
|
NEEDED_NIPS="001 $NEEDED_NIPS"
|
||||||
print_info "Added NIP-001 (required for core functionality)"
|
print_info "Added NIP-001 (required for core functionality)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ AUTODETECT SYSTEM ARCHITECTURE
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
|
||||||
# Determine architecture
|
# Determine architecture
|
||||||
if [ -z "$ARCHITECTURE" ]; then
|
if [ -z "$ARCHITECTURE" ]; then
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
|
@ -202,13 +258,20 @@ if ! command -v $CC &> /dev/null; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build source file list - Core crypto dependencies
|
|
||||||
SOURCES="nostr_core/crypto/nostr_crypto.c"
|
|
||||||
SOURCES="$SOURCES nostr_core/crypto/nostr_secp256k1.c"
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ ADD CORE DEPENDENCIES THAT NEED TO BE BUILT TO THE $SOURCES VARIABLE
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
|
||||||
|
SOURCES="nostr_core/crypto/nostr_secp256k1.c"
|
||||||
SOURCES="$SOURCES nostr_core/crypto/nostr_aes.c"
|
SOURCES="$SOURCES nostr_core/crypto/nostr_aes.c"
|
||||||
SOURCES="$SOURCES nostr_core/crypto/nostr_chacha20.c"
|
SOURCES="$SOURCES nostr_core/crypto/nostr_chacha20.c"
|
||||||
SOURCES="$SOURCES cjson/cJSON.c"
|
SOURCES="$SOURCES cjson/cJSON.c"
|
||||||
SOURCES="$SOURCES nostr_core/utils.c"
|
SOURCES="$SOURCES nostr_core/utils.c"
|
||||||
|
SOURCES="$SOURCES nostr_core/nostr_common.c"
|
||||||
|
|
||||||
# Add secp256k1 library path based on architecture
|
# Add secp256k1 library path based on architecture
|
||||||
case $ARCHITECTURE in
|
case $ARCHITECTURE in
|
||||||
|
@ -227,6 +290,7 @@ for nip in $NEEDED_NIPS; do
|
||||||
SOURCES="$SOURCES $NIP_FILE"
|
SOURCES="$SOURCES $NIP_FILE"
|
||||||
case $nip in
|
case $nip in
|
||||||
001) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-001(Basic)" ;;
|
001) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-001(Basic)" ;;
|
||||||
|
004) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-004(Encrypt)" ;;
|
||||||
005) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-005(DNS)" ;;
|
005) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-005(DNS)" ;;
|
||||||
006) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-006(Keys)" ;;
|
006) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-006(Keys)" ;;
|
||||||
011) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-011(Relay-Info)" ;;
|
011) NIP_DESCRIPTIONS="$NIP_DESCRIPTIONS NIP-011(Relay-Info)" ;;
|
||||||
|
@ -259,7 +323,14 @@ if [ "$VERBOSE" = true ]; then
|
||||||
print_info "Flags: $CFLAGS $INCLUDES"
|
print_info "Flags: $CFLAGS $INCLUDES"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Compile each source file to object file
|
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ COMPILE EACH SOURCE FROM $SOURCES INTO A .o FILE
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
|
||||||
OBJECTS=""
|
OBJECTS=""
|
||||||
for source in $SOURCES; do
|
for source in $SOURCES; do
|
||||||
if [ -f "$source" ]; then
|
if [ -f "$source" ]; then
|
||||||
|
@ -270,7 +341,11 @@ for source in $SOURCES; do
|
||||||
print_info "Compiling: $source -> $obj_name"
|
print_info "Compiling: $source -> $obj_name"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# THE ACTUAL COMMAND TO COMPILE .c FILES
|
||||||
|
#################################################
|
||||||
$CC $CFLAGS $INCLUDES -c "$source" -o "$obj_name"
|
$CC $CFLAGS $INCLUDES -c "$source" -o "$obj_name"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
print_error "Failed to compile $source"
|
print_error "Failed to compile $source"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -281,7 +356,13 @@ for source in $SOURCES; do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Create self-contained static library (extract all objects first)
|
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ CREATE THE FINAL STATIC LIBRARY FOR THE PROJECT: libnostr_core_XX.a
|
||||||
|
############ BY LINKING IN ALL OUR .o FILES THAT ARE REQUESTED TO BE ADDED.
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
print_info "Creating self-contained static library: $OUTPUT"
|
print_info "Creating self-contained static library: $OUTPUT"
|
||||||
|
|
||||||
# Create temporary directories for extracting objects
|
# Create temporary directories for extracting objects
|
||||||
|
@ -316,12 +397,26 @@ fi
|
||||||
if [ "$VERBOSE" = true ]; then
|
if [ "$VERBOSE" = true ]; then
|
||||||
print_info "Combining all objects into self-contained library..."
|
print_info "Combining all objects into self-contained library..."
|
||||||
fi
|
fi
|
||||||
ar rcs "$OUTPUT" $OBJECTS "$TMP_SECP256K1"/*.o "$TMP_OPENSSL"/*.o "$TMP_CURL"/*.o 2>/dev/null
|
|
||||||
|
|
||||||
|
#########################################################
|
||||||
|
### THE ACTUAL COMMAND TO LINK .o FILES INTO A .a FILE
|
||||||
|
#########################################################
|
||||||
|
ar rcs "$OUTPUT" $OBJECTS "$TMP_SECP256K1"/*.o "$TMP_OPENSSL"/*.o "$TMP_CURL"/*.o
|
||||||
|
AR_RESULT=$?
|
||||||
|
|
||||||
# Cleanup temporary directories
|
# Cleanup temporary directories
|
||||||
rm -rf "$TMP_SECP256K1" "$TMP_OPENSSL" "$TMP_CURL"
|
rm -rf "$TMP_SECP256K1" "$TMP_OPENSSL" "$TMP_CURL"
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
|
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
############ IF THE LINKING OCCURED SUCCESSFULLY, BUILD THE TEST FILE EXECUTABLES
|
||||||
|
############ BY LINKING IN ALL OUR .o FILES THAT ARE REQUESTED TO BE ADDED.
|
||||||
|
###########################################################################################
|
||||||
|
###########################################################################################
|
||||||
|
if [ $AR_RESULT -eq 0 ]; then
|
||||||
# Cleanup object files
|
# Cleanup object files
|
||||||
rm -f $OBJECTS
|
rm -f $OBJECTS
|
||||||
|
|
||||||
|
@ -347,36 +442,18 @@ if [ $? -eq 0 ]; then
|
||||||
|
|
||||||
print_info "Building test: $test_name"
|
print_info "Building test: $test_name"
|
||||||
|
|
||||||
# Determine linking requirements based on file content
|
# Simple test compilation - everything is in our fat library
|
||||||
LINK_FLAGS="-lm -static"
|
LINK_FLAGS="-lz -ldl -lpthread -lm -static"
|
||||||
|
|
||||||
# Always include secp256k1 library if available
|
|
||||||
if [ -f "$SECP256K1_LIB" ]; then
|
|
||||||
LINK_FLAGS="$SECP256K1_LIB $LINK_FLAGS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if test needs curl/SSL libraries (NIP-05/NIP-11)
|
|
||||||
if grep -q -E 'nip005|nip011|curl/curl\.h' "$test_file" 2>/dev/null; then
|
|
||||||
# Check if curl and SSL libraries are available
|
|
||||||
if [ -f "./curl-install/lib/libcurl.a" ] && [ -f "./openssl-install/lib64/libssl.a" ]; then
|
|
||||||
LINK_FLAGS="./curl-install/lib/libcurl.a ./openssl-install/lib64/libssl.a ./openssl-install/lib64/libcrypto.a -lz -ldl -lpthread $LINK_FLAGS"
|
|
||||||
if [ "$VERBOSE" = true ]; then
|
|
||||||
print_info " Using full static SSL/curl linking for $test_name"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
print_warning " Test $test_name needs curl/SSL but libraries not found - using basic linking"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Compile the test
|
|
||||||
if [ "$VERBOSE" = true ]; then
|
if [ "$VERBOSE" = true ]; then
|
||||||
print_info " Command: $CC $CFLAGS $INCLUDES \"$test_file\" -o \"$test_exe\" ./$OUTPUT $LINK_FLAGS"
|
print_info " Command: $CC $CFLAGS $INCLUDES \"$test_file\" -o \"$test_exe\" ./$OUTPUT $LINK_FLAGS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if $CC $CFLAGS $INCLUDES "$test_file" -o "$test_exe" "./$OUTPUT" $LINK_FLAGS 2>/dev/null; then
|
if $CC $CFLAGS $INCLUDES "$test_file" -o "$test_exe" "./$OUTPUT" $LINK_FLAGS; then
|
||||||
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
SUCCESS_COUNT=$((SUCCESS_COUNT + 1))
|
||||||
|
print_success "Built $test_name"
|
||||||
if [ "$VERBOSE" = true ]; then
|
if [ "$VERBOSE" = true ]; then
|
||||||
print_success " Built: $test_exe"
|
print_info " Executable: $test_exe"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print_error " Failed to build: $test_name"
|
print_error " Failed to build: $test_name"
|
||||||
|
@ -394,7 +471,7 @@ if [ $? -eq 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Usage in your project:"
|
echo "Usage in your project:"
|
||||||
echo " gcc your_app.c $OUTPUT -lz -ldl -lpthread -o your_app"
|
echo " gcc your_app.c $OUTPUT -lz -ldl -lpthread -lm -o your_app"
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
print_error "Failed to create static library"
|
print_error "Failed to create static library"
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
@PACKAGE_INIT@
|
|
||||||
|
|
||||||
include(CMakeFindDependencyMacro)
|
|
||||||
|
|
||||||
# Find required dependencies
|
|
||||||
find_dependency(Threads REQUIRED)
|
|
||||||
|
|
||||||
# Include targets
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/nostr_core-targets.cmake")
|
|
||||||
|
|
||||||
# Set variables for backward compatibility
|
|
||||||
set(NOSTR_CORE_FOUND TRUE)
|
|
||||||
set(NOSTR_CORE_VERSION "@PROJECT_VERSION@")
|
|
||||||
|
|
||||||
# Check which libraries are available
|
|
||||||
set(NOSTR_CORE_STATIC_AVAILABLE FALSE)
|
|
||||||
set(NOSTR_CORE_SHARED_AVAILABLE FALSE)
|
|
||||||
|
|
||||||
if(TARGET nostr_core::static)
|
|
||||||
set(NOSTR_CORE_STATIC_AVAILABLE TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TARGET nostr_core::shared)
|
|
||||||
set(NOSTR_CORE_SHARED_AVAILABLE TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Provide convenient variables
|
|
||||||
if(NOSTR_CORE_STATIC_AVAILABLE)
|
|
||||||
set(NOSTR_CORE_LIBRARIES nostr_core::static)
|
|
||||||
elseif(NOSTR_CORE_SHARED_AVAILABLE)
|
|
||||||
set(NOSTR_CORE_LIBRARIES nostr_core::shared)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(NOSTR_CORE_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@/nostr")
|
|
||||||
|
|
||||||
# Feature information
|
|
||||||
set(NOSTR_CORE_ENABLE_WEBSOCKETS @NOSTR_ENABLE_WEBSOCKETS@)
|
|
||||||
set(NOSTR_CORE_USE_MBEDTLS @NOSTR_USE_MBEDTLS@)
|
|
||||||
|
|
||||||
check_required_components(nostr_core)
|
|
BIN
libnostr_core.a
BIN
libnostr_core.a
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -1,186 +0,0 @@
|
||||||
/*
|
|
||||||
* NOSTR Crypto - Self-contained cryptographic functions
|
|
||||||
*
|
|
||||||
* Embedded implementations of crypto primitives needed for NOSTR
|
|
||||||
* No external dependencies except standard C library
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef NOSTR_CRYPTO_H
|
|
||||||
#define NOSTR_CRYPTO_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// CORE CRYPTO FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// Initialize crypto subsystem
|
|
||||||
int nostr_crypto_init(void);
|
|
||||||
|
|
||||||
// Cleanup crypto subsystem
|
|
||||||
void nostr_crypto_cleanup(void);
|
|
||||||
|
|
||||||
// SHA-256 hash function
|
|
||||||
int nostr_sha256(const unsigned char* data, size_t len, unsigned char* hash);
|
|
||||||
|
|
||||||
// HMAC-SHA256
|
|
||||||
int nostr_hmac_sha256(const unsigned char* key, size_t key_len,
|
|
||||||
const unsigned char* data, size_t data_len,
|
|
||||||
unsigned char* output);
|
|
||||||
|
|
||||||
// HMAC-SHA512
|
|
||||||
int nostr_hmac_sha512(const unsigned char* key, size_t key_len,
|
|
||||||
const unsigned char* data, size_t data_len,
|
|
||||||
unsigned char* output);
|
|
||||||
|
|
||||||
// PBKDF2 with HMAC-SHA512
|
|
||||||
int nostr_pbkdf2_hmac_sha512(const unsigned char* password, size_t password_len,
|
|
||||||
const unsigned char* salt, size_t salt_len,
|
|
||||||
int iterations,
|
|
||||||
unsigned char* output, size_t output_len);
|
|
||||||
|
|
||||||
// SHA-512 implementation (for testing)
|
|
||||||
int nostr_sha512(const unsigned char* data, size_t len, unsigned char* hash);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// SECP256K1 ELLIPTIC CURVE FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// Verify private key is valid
|
|
||||||
int nostr_ec_private_key_verify(const unsigned char* private_key);
|
|
||||||
|
|
||||||
// Generate public key from private key
|
|
||||||
int nostr_ec_public_key_from_private_key(const unsigned char* private_key,
|
|
||||||
unsigned char* public_key);
|
|
||||||
|
|
||||||
// Sign data with ECDSA
|
|
||||||
int nostr_ec_sign(const unsigned char* private_key,
|
|
||||||
const unsigned char* hash,
|
|
||||||
unsigned char* signature);
|
|
||||||
|
|
||||||
// RFC 6979 deterministic nonce generation
|
|
||||||
int nostr_rfc6979_generate_k(const unsigned char* private_key,
|
|
||||||
const unsigned char* message_hash,
|
|
||||||
unsigned char* k_out);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// HKDF KEY DERIVATION FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// HKDF Extract step
|
|
||||||
int nostr_hkdf_extract(const unsigned char* salt, size_t salt_len,
|
|
||||||
const unsigned char* ikm, size_t ikm_len,
|
|
||||||
unsigned char* prk);
|
|
||||||
|
|
||||||
// HKDF Expand step
|
|
||||||
int nostr_hkdf_expand(const unsigned char* prk, size_t prk_len,
|
|
||||||
const unsigned char* info, size_t info_len,
|
|
||||||
unsigned char* okm, size_t okm_len);
|
|
||||||
|
|
||||||
// HKDF (Extract + Expand)
|
|
||||||
int nostr_hkdf(const unsigned char* salt, size_t salt_len,
|
|
||||||
const unsigned char* ikm, size_t ikm_len,
|
|
||||||
const unsigned char* info, size_t info_len,
|
|
||||||
unsigned char* okm, size_t okm_len);
|
|
||||||
|
|
||||||
// ECDH shared secret computation (for debugging)
|
|
||||||
int ecdh_shared_secret(const unsigned char* private_key,
|
|
||||||
const unsigned char* public_key_x,
|
|
||||||
unsigned char* shared_secret);
|
|
||||||
|
|
||||||
// Base64 encoding function (for debugging)
|
|
||||||
size_t base64_encode(const unsigned char* data, size_t len, char* output, size_t output_size);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// NIP-04 AND NIP-44 ENCRYPTION FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// Note: NOSTR_NIP04_MAX_PLAINTEXT_SIZE already defined in nostr_core.h
|
|
||||||
#define NOSTR_NIP44_MAX_PLAINTEXT_SIZE 65536
|
|
||||||
|
|
||||||
// NIP-04 encryption (AES-256-CBC)
|
|
||||||
int nostr_nip04_encrypt(const unsigned char* sender_private_key,
|
|
||||||
const unsigned char* recipient_public_key,
|
|
||||||
const char* plaintext,
|
|
||||||
char* output,
|
|
||||||
size_t output_size);
|
|
||||||
|
|
||||||
// NIP-04 decryption
|
|
||||||
int nostr_nip04_decrypt(const unsigned char* recipient_private_key,
|
|
||||||
const unsigned char* sender_public_key,
|
|
||||||
const char* encrypted_data,
|
|
||||||
char* output,
|
|
||||||
size_t output_size);
|
|
||||||
|
|
||||||
// NIP-44 encryption (ChaCha20-Poly1305)
|
|
||||||
int nostr_nip44_encrypt(const unsigned char* sender_private_key,
|
|
||||||
const unsigned char* recipient_public_key,
|
|
||||||
const char* plaintext,
|
|
||||||
char* output,
|
|
||||||
size_t output_size);
|
|
||||||
|
|
||||||
// NIP-44 encryption with fixed nonce (for testing)
|
|
||||||
int nostr_nip44_encrypt_with_nonce(const unsigned char* sender_private_key,
|
|
||||||
const unsigned char* recipient_public_key,
|
|
||||||
const char* plaintext,
|
|
||||||
const unsigned char* nonce,
|
|
||||||
char* output,
|
|
||||||
size_t output_size);
|
|
||||||
|
|
||||||
// NIP-44 decryption
|
|
||||||
int nostr_nip44_decrypt(const unsigned char* recipient_private_key,
|
|
||||||
const unsigned char* sender_public_key,
|
|
||||||
const char* encrypted_data,
|
|
||||||
char* output,
|
|
||||||
size_t output_size);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// BIP39 MNEMONIC FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// Generate mnemonic from entropy
|
|
||||||
int nostr_bip39_mnemonic_from_bytes(const unsigned char* entropy, size_t entropy_len,
|
|
||||||
char* mnemonic);
|
|
||||||
|
|
||||||
// Validate mnemonic
|
|
||||||
int nostr_bip39_mnemonic_validate(const char* mnemonic);
|
|
||||||
|
|
||||||
// Convert mnemonic to seed
|
|
||||||
int nostr_bip39_mnemonic_to_seed(const char* mnemonic, const char* passphrase,
|
|
||||||
unsigned char* seed, size_t seed_len);
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// BIP32 HD WALLET FUNCTIONS
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char private_key[32];
|
|
||||||
unsigned char public_key[33];
|
|
||||||
unsigned char chain_code[32];
|
|
||||||
uint32_t depth;
|
|
||||||
uint32_t parent_fingerprint;
|
|
||||||
uint32_t child_number;
|
|
||||||
} nostr_hd_key_t;
|
|
||||||
|
|
||||||
// Create master key from seed
|
|
||||||
int nostr_bip32_key_from_seed(const unsigned char* seed, size_t seed_len,
|
|
||||||
nostr_hd_key_t* master_key);
|
|
||||||
|
|
||||||
// Derive child key from parent
|
|
||||||
int nostr_bip32_derive_child(const nostr_hd_key_t* parent_key, uint32_t child_number,
|
|
||||||
nostr_hd_key_t* child_key);
|
|
||||||
|
|
||||||
// Derive key from path
|
|
||||||
int nostr_bip32_derive_path(const nostr_hd_key_t* master_key, const uint32_t* path,
|
|
||||||
size_t path_len, nostr_hd_key_t* derived_key);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // NOSTR_CRYPTO_H
|
|
|
@ -5,57 +5,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nip001.h"
|
#include "nip001.h"
|
||||||
#include "nostr_crypto.h"
|
#include "utils.h"
|
||||||
#include "../cjson/cJSON.h"
|
#include "../cjson/cJSON.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
// Declare utility functions
|
// Declare utility functions
|
||||||
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex);
|
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex);
|
||||||
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t len);
|
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t len);
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the NOSTR library
|
|
||||||
*/
|
|
||||||
int nostr_init(void) {
|
|
||||||
if (nostr_crypto_init() != 0) {
|
|
||||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
|
||||||
}
|
|
||||||
return NOSTR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup the NOSTR library
|
|
||||||
*/
|
|
||||||
void nostr_cleanup(void) {
|
|
||||||
nostr_crypto_cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert error code to human-readable string
|
|
||||||
*/
|
|
||||||
const char* nostr_strerror(int error_code) {
|
|
||||||
switch (error_code) {
|
|
||||||
case NOSTR_SUCCESS: return "Success";
|
|
||||||
case NOSTR_ERROR_INVALID_INPUT: return "Invalid input";
|
|
||||||
case NOSTR_ERROR_CRYPTO_FAILED: return "Cryptographic operation failed";
|
|
||||||
case NOSTR_ERROR_MEMORY_FAILED: return "Memory allocation failed";
|
|
||||||
case NOSTR_ERROR_IO_FAILED: return "I/O operation failed";
|
|
||||||
case NOSTR_ERROR_NETWORK_FAILED: return "Network operation failed";
|
|
||||||
case NOSTR_ERROR_NIP04_INVALID_FORMAT: return "NIP-04 invalid format";
|
|
||||||
case NOSTR_ERROR_NIP04_DECRYPT_FAILED: return "NIP-04 decryption failed";
|
|
||||||
case NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL: return "NIP-04 buffer too small";
|
|
||||||
case NOSTR_ERROR_NIP05_INVALID_IDENTIFIER: return "NIP-05: Invalid identifier format";
|
|
||||||
case NOSTR_ERROR_NIP05_HTTP_FAILED: return "NIP-05: HTTP request failed";
|
|
||||||
case NOSTR_ERROR_NIP05_JSON_PARSE_FAILED: return "NIP-05: JSON parsing failed";
|
|
||||||
case NOSTR_ERROR_NIP05_NAME_NOT_FOUND: return "NIP-05: Name not found in .well-known";
|
|
||||||
case NOSTR_ERROR_NIP05_PUBKEY_MISMATCH: return "NIP-05: Public key mismatch";
|
|
||||||
default: return "Unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and sign a NOSTR event
|
* Create and sign a NOSTR event
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,26 +11,8 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "../cjson/cJSON.h"
|
#include "../cjson/cJSON.h"
|
||||||
|
|
||||||
// Error codes
|
|
||||||
#define NOSTR_SUCCESS 0
|
|
||||||
#define NOSTR_ERROR_INVALID_INPUT -1
|
|
||||||
#define NOSTR_ERROR_CRYPTO_FAILED -2
|
|
||||||
#define NOSTR_ERROR_MEMORY_FAILED -3
|
|
||||||
#define NOSTR_ERROR_IO_FAILED -4
|
|
||||||
#define NOSTR_ERROR_NETWORK_FAILED -5
|
|
||||||
#define NOSTR_ERROR_NIP04_INVALID_FORMAT -10
|
|
||||||
#define NOSTR_ERROR_NIP04_DECRYPT_FAILED -11
|
|
||||||
#define NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL -12
|
|
||||||
#define NOSTR_ERROR_NIP05_INVALID_IDENTIFIER -20
|
|
||||||
#define NOSTR_ERROR_NIP05_HTTP_FAILED -21
|
|
||||||
#define NOSTR_ERROR_NIP05_JSON_PARSE_FAILED -22
|
|
||||||
#define NOSTR_ERROR_NIP05_NAME_NOT_FOUND -23
|
|
||||||
#define NOSTR_ERROR_NIP05_PUBKEY_MISMATCH -24
|
|
||||||
|
|
||||||
// Function declarations
|
// Function declarations
|
||||||
int nostr_init(void);
|
|
||||||
void nostr_cleanup(void);
|
|
||||||
const char* nostr_strerror(int error_code);
|
|
||||||
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags, const unsigned char* private_key, time_t timestamp);
|
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags, const unsigned char* private_key, time_t timestamp);
|
||||||
|
|
||||||
#endif // NIP001_H
|
#endif // NIP001_H
|
||||||
|
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* NIP-04: Encrypted Direct Message Implementation
|
||||||
|
* https://github.com/nostr-protocol/nips/blob/master/04.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nip004.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "nostr_common.h"
|
||||||
|
#include "crypto/nostr_secp256k1.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Include our AES implementation
|
||||||
|
#include "crypto/nostr_aes.h"
|
||||||
|
|
||||||
|
// Forward declarations for internal functions
|
||||||
|
static int aes_cbc_encrypt(const unsigned char* key, const unsigned char* iv,
|
||||||
|
const unsigned char* input, size_t input_len,
|
||||||
|
unsigned char* output);
|
||||||
|
static int aes_cbc_decrypt(const unsigned char* key, const unsigned char* iv,
|
||||||
|
const unsigned char* input, size_t input_len,
|
||||||
|
unsigned char* output);
|
||||||
|
static size_t pkcs7_pad(unsigned char* data, size_t data_len, size_t block_size);
|
||||||
|
static size_t pkcs7_unpad(unsigned char* data, size_t data_len);
|
||||||
|
|
||||||
|
// Memory clearing utility
|
||||||
|
static void memory_clear(const void *p, size_t len) {
|
||||||
|
if (p && len) {
|
||||||
|
memset((void *)p, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// AES-256-CBC ENCRYPTION/DECRYPTION USING TINYAES
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
static int aes_cbc_encrypt(const unsigned char* key, const unsigned char* iv,
|
||||||
|
const unsigned char* input, size_t input_len,
|
||||||
|
unsigned char* output) {
|
||||||
|
if (!key || !iv || !input || !output || input_len % 16 != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize AES context with key and IV
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
AES_init_ctx_iv(&ctx, key, iv);
|
||||||
|
|
||||||
|
// Copy input to output (tinyAES works in-place)
|
||||||
|
memcpy(output, input, input_len);
|
||||||
|
|
||||||
|
// Encrypt using AES-256-CBC
|
||||||
|
AES_CBC_encrypt_buffer(&ctx, output, input_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aes_cbc_decrypt(const unsigned char* key, const unsigned char* iv,
|
||||||
|
const unsigned char* input, size_t input_len,
|
||||||
|
unsigned char* output) {
|
||||||
|
if (!key || !iv || !input || !output || input_len % 16 != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize AES context with key and IV
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
AES_init_ctx_iv(&ctx, key, iv);
|
||||||
|
|
||||||
|
// Copy input to output (tinyAES works in-place)
|
||||||
|
memcpy(output, input, input_len);
|
||||||
|
|
||||||
|
// Decrypt using AES-256-CBC
|
||||||
|
AES_CBC_decrypt_buffer(&ctx, output, input_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PKCS#7 padding functions
|
||||||
|
static size_t pkcs7_pad(unsigned char* data, size_t data_len, size_t block_size) {
|
||||||
|
size_t padding = block_size - (data_len % block_size);
|
||||||
|
for (size_t i = 0; i < padding; i++) {
|
||||||
|
data[data_len + i] = (unsigned char)padding;
|
||||||
|
}
|
||||||
|
return data_len + padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t pkcs7_unpad(unsigned char* data, size_t data_len) {
|
||||||
|
if (data_len == 0) return 0;
|
||||||
|
|
||||||
|
unsigned char padding = data[data_len - 1];
|
||||||
|
if (padding == 0 || padding > 16) return 0; // Invalid padding
|
||||||
|
|
||||||
|
// Verify padding
|
||||||
|
for (size_t i = data_len - padding; i < data_len; i++) {
|
||||||
|
if (data[i] != padding) return 0; // Invalid padding
|
||||||
|
}
|
||||||
|
|
||||||
|
return data_len - padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// NIP-04 IMPLEMENTATION
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
int nostr_nip04_encrypt(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
char* output,
|
||||||
|
size_t output_size) {
|
||||||
|
if (!sender_private_key || !recipient_public_key || !plaintext || !output) {
|
||||||
|
return NOSTR_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t plaintext_len = strlen(plaintext);
|
||||||
|
|
||||||
|
if (plaintext_len > NOSTR_NIP04_MAX_PLAINTEXT_SIZE) {
|
||||||
|
return NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIX: Calculate final size requirements EARLY before any allocations
|
||||||
|
// CRITICAL: Account for PKCS#7 padding which ALWAYS adds 1-16 bytes
|
||||||
|
// If plaintext_len is a multiple of 16, PKCS#7 adds a full 16-byte block
|
||||||
|
size_t padded_len = ((plaintext_len / 16) + 1) * 16; // Always add one full block for PKCS#7
|
||||||
|
size_t ciphertext_b64_max = ((padded_len + 2) / 3) * 4 + 1;
|
||||||
|
size_t iv_b64_max = ((16 + 2) / 3) * 4 + 1; // Always 25 bytes
|
||||||
|
size_t estimated_result_len = ciphertext_b64_max + 4 + iv_b64_max; // +4 for "?iv="
|
||||||
|
|
||||||
|
// FIX: Check output buffer size BEFORE doing any work
|
||||||
|
if (estimated_result_len > output_size) {
|
||||||
|
return NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Compute ECDH shared secret
|
||||||
|
unsigned char shared_secret[32];
|
||||||
|
if (ecdh_shared_secret(sender_private_key, recipient_public_key, shared_secret) != 0) {
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Generate random IV (16 bytes)
|
||||||
|
unsigned char iv[16];
|
||||||
|
if (nostr_secp256k1_get_random_bytes(iv, 16) != 1) {
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Pad plaintext using PKCS#7
|
||||||
|
unsigned char* padded_data = malloc(padded_len);
|
||||||
|
if (!padded_data) {
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(padded_data, plaintext, plaintext_len);
|
||||||
|
size_t actual_padded_len = pkcs7_pad(padded_data, plaintext_len, 16);
|
||||||
|
|
||||||
|
// Step 4: Encrypt using AES-256-CBC
|
||||||
|
unsigned char* ciphertext = malloc(padded_len);
|
||||||
|
if (!ciphertext) {
|
||||||
|
free(padded_data);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aes_cbc_encrypt(shared_secret, iv, padded_data, actual_padded_len, ciphertext) != 0) {
|
||||||
|
free(padded_data);
|
||||||
|
free(ciphertext);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Base64 encode ciphertext and IV
|
||||||
|
size_t ciphertext_b64_len = ((actual_padded_len + 2) / 3) * 4 + 1;
|
||||||
|
size_t iv_b64_len = ((16 + 2) / 3) * 4 + 1;
|
||||||
|
|
||||||
|
char* ciphertext_b64 = malloc(ciphertext_b64_len);
|
||||||
|
char* iv_b64 = malloc(iv_b64_len);
|
||||||
|
|
||||||
|
if (!ciphertext_b64 || !iv_b64) {
|
||||||
|
free(padded_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(iv_b64);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIX: Pass buffer sizes to base64_encode and check for success
|
||||||
|
size_t ct_b64_len = base64_encode(ciphertext, actual_padded_len, ciphertext_b64, ciphertext_b64_len);
|
||||||
|
size_t iv_b64_len_actual = base64_encode(iv, 16, iv_b64, iv_b64_len);
|
||||||
|
|
||||||
|
// FIX: Check if encoding succeeded
|
||||||
|
if (ct_b64_len == 0 || iv_b64_len_actual == 0) {
|
||||||
|
free(padded_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(iv_b64);
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Format as "ciphertext?iv=iv_base64" - size check moved earlier, now guaranteed to fit
|
||||||
|
size_t result_len = ct_b64_len + 4 + iv_b64_len_actual + 1; // +4 for "?iv=", +1 for null
|
||||||
|
|
||||||
|
if (result_len > output_size) {
|
||||||
|
free(padded_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(iv_b64);
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
return NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(output, output_size, "%s?iv=%s", ciphertext_b64, iv_b64);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(padded_data, padded_len);
|
||||||
|
memory_clear(ciphertext, padded_len);
|
||||||
|
free(padded_data);
|
||||||
|
free(ciphertext);
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(iv_b64);
|
||||||
|
|
||||||
|
return NOSTR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nostr_nip04_decrypt(const unsigned char* recipient_private_key,
|
||||||
|
const unsigned char* sender_public_key,
|
||||||
|
const char* encrypted_data,
|
||||||
|
char* output,
|
||||||
|
size_t output_size) {
|
||||||
|
if (!recipient_private_key || !sender_public_key || !encrypted_data || !output) {
|
||||||
|
return NOSTR_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Parse encrypted data format "ciphertext?iv=iv_base64"
|
||||||
|
char* separator = strstr(encrypted_data, "?iv=");
|
||||||
|
if (!separator) {
|
||||||
|
return NOSTR_ERROR_NIP04_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ciphertext_b64_len = separator - encrypted_data;
|
||||||
|
const char* iv_b64 = separator + 4; // Skip "?iv="
|
||||||
|
|
||||||
|
if (ciphertext_b64_len == 0 || strlen(iv_b64) == 0) {
|
||||||
|
return NOSTR_ERROR_NIP04_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Create null-terminated copy of ciphertext base64
|
||||||
|
char* ciphertext_b64 = malloc(ciphertext_b64_len + 1);
|
||||||
|
if (!ciphertext_b64) {
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ciphertext_b64, encrypted_data, ciphertext_b64_len);
|
||||||
|
ciphertext_b64[ciphertext_b64_len] = '\0';
|
||||||
|
|
||||||
|
// Step 3: Calculate proper buffer sizes for decoded data
|
||||||
|
// Base64 decoding: 4 chars -> 3 bytes, so max decoded size is (len * 3) / 4
|
||||||
|
size_t max_ciphertext_len = ((ciphertext_b64_len + 3) / 4) * 3;
|
||||||
|
size_t max_iv_len = ((strlen(iv_b64) + 3) / 4) * 3;
|
||||||
|
|
||||||
|
// Allocate buffers with proper sizes
|
||||||
|
unsigned char* ciphertext = malloc(max_ciphertext_len);
|
||||||
|
unsigned char* iv_buffer = malloc(max_iv_len);
|
||||||
|
|
||||||
|
if (!ciphertext || !iv_buffer) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(iv_buffer);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Base64 decode ciphertext and IV
|
||||||
|
size_t ciphertext_len = base64_decode(ciphertext_b64, ciphertext);
|
||||||
|
size_t iv_len = base64_decode(iv_b64, iv_buffer);
|
||||||
|
|
||||||
|
if (ciphertext_len == 0 || iv_len != 16 || ciphertext_len % 16 != 0) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(iv_buffer);
|
||||||
|
return NOSTR_ERROR_NIP04_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy IV to fixed-size buffer for safety
|
||||||
|
unsigned char iv[16];
|
||||||
|
memcpy(iv, iv_buffer, 16);
|
||||||
|
free(iv_buffer);
|
||||||
|
|
||||||
|
// Step 5: Compute ECDH shared secret
|
||||||
|
unsigned char shared_secret[32];
|
||||||
|
if (ecdh_shared_secret(recipient_private_key, sender_public_key, shared_secret) != 0) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Decrypt using AES-256-CBC
|
||||||
|
unsigned char* plaintext_padded = malloc(ciphertext_len);
|
||||||
|
if (!plaintext_padded) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aes_cbc_decrypt(shared_secret, iv, ciphertext, ciphertext_len, plaintext_padded) != 0) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(plaintext_padded);
|
||||||
|
return NOSTR_ERROR_NIP04_DECRYPT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Remove PKCS#7 padding
|
||||||
|
size_t plaintext_len = pkcs7_unpad(plaintext_padded, ciphertext_len);
|
||||||
|
if (plaintext_len == 0 || plaintext_len > ciphertext_len) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(plaintext_padded);
|
||||||
|
return NOSTR_ERROR_NIP04_DECRYPT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: Copy to output buffer and null-terminate
|
||||||
|
if (plaintext_len + 1 > output_size) {
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(plaintext_padded);
|
||||||
|
return NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(output, plaintext_padded, plaintext_len);
|
||||||
|
output[plaintext_len] = '\0';
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(plaintext_padded, ciphertext_len);
|
||||||
|
free(ciphertext_b64);
|
||||||
|
free(ciphertext);
|
||||||
|
free(plaintext_padded);
|
||||||
|
|
||||||
|
return NOSTR_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* NIP-04: Encrypted Direct Message
|
||||||
|
* https://github.com/nostr-protocol/nips/blob/master/04.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOSTR_NIP004_H
|
||||||
|
#define NOSTR_NIP004_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NIP-04 constants
|
||||||
|
// #define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 65535
|
||||||
|
// NIP-04 Constants
|
||||||
|
// #define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 16777216 // 16MB
|
||||||
|
// #define NOSTR_NIP04_MAX_ENCRYPTED_SIZE 22369621 // ~21.3MB (accounts for base64 overhead + IV)
|
||||||
|
/**
|
||||||
|
* NIP-04: Encrypt a message using ECDH + AES-256-CBC
|
||||||
|
*
|
||||||
|
* @param sender_private_key 32-byte sender private key
|
||||||
|
* @param recipient_public_key 32-byte recipient public key (x-only)
|
||||||
|
* @param plaintext Message to encrypt
|
||||||
|
* @param output Buffer for encrypted output (format: "ciphertext?iv=iv_base64")
|
||||||
|
* @param output_size Size of output buffer
|
||||||
|
* @return NOSTR_SUCCESS on success, error code on failure
|
||||||
|
*/
|
||||||
|
int nostr_nip04_encrypt(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
char* output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-04: Decrypt a message using ECDH + AES-256-CBC
|
||||||
|
*
|
||||||
|
* @param recipient_private_key 32-byte recipient private key
|
||||||
|
* @param sender_public_key 32-byte sender public key (x-only)
|
||||||
|
* @param encrypted_data Encrypted message (format: "ciphertext?iv=iv_base64")
|
||||||
|
* @param output Buffer for decrypted plaintext
|
||||||
|
* @param output_size Size of output buffer
|
||||||
|
* @return NOSTR_SUCCESS on success, error code on failure
|
||||||
|
*/
|
||||||
|
int nostr_nip04_decrypt(const unsigned char* recipient_private_key,
|
||||||
|
const unsigned char* sender_public_key,
|
||||||
|
const char* encrypted_data,
|
||||||
|
char* output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NOSTR_NIP004_H
|
|
@ -4,23 +4,16 @@
|
||||||
|
|
||||||
#include "nip005.h"
|
#include "nip005.h"
|
||||||
#include "../cjson/cJSON.h"
|
#include "../cjson/cJSON.h"
|
||||||
|
#include "nostr_common.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h> // For strcasecmp
|
#include <strings.h> // For strcasecmp
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#ifndef DISABLE_NIP05
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
// Maximum sizes for NIP-05 operations
|
|
||||||
#define NIP05_MAX_URL_SIZE 512
|
|
||||||
#define NIP05_MAX_RESPONSE_SIZE 8192
|
|
||||||
#define NIP05_MAX_IDENTIFIER_SIZE 256
|
|
||||||
#define NIP05_DEFAULT_TIMEOUT 10
|
|
||||||
|
|
||||||
#ifndef DISABLE_NIP05
|
|
||||||
|
|
||||||
// Structure for HTTP response handling
|
// Structure for HTTP response handling
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -278,7 +271,7 @@ int nostr_nip05_lookup(const char* nip05_identifier, char* pubkey_hex_out,
|
||||||
|
|
||||||
char local_part[64];
|
char local_part[64];
|
||||||
char domain[256];
|
char domain[256];
|
||||||
char url[NIP05_MAX_URL_SIZE];
|
char url[NOSTR_MAX_URL_SIZE];
|
||||||
|
|
||||||
// Parse the identifier
|
// Parse the identifier
|
||||||
int parse_result = nip05_parse_identifier(nip05_identifier, local_part, domain);
|
int parse_result = nip05_parse_identifier(nip05_identifier, local_part, domain);
|
||||||
|
@ -348,41 +341,4 @@ int nostr_nip05_verify(const char* nip05_identifier, const char* pubkey_hex,
|
||||||
}
|
}
|
||||||
|
|
||||||
return NOSTR_SUCCESS;
|
return NOSTR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // DISABLE_NIP05
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stub implementations when NIP-05 is disabled at compile time
|
|
||||||
*/
|
|
||||||
int nostr_nip05_parse_well_known(const char* json_response, const char* local_part,
|
|
||||||
char* pubkey_hex_out, char*** relays, int* relay_count) {
|
|
||||||
(void)json_response;
|
|
||||||
(void)local_part;
|
|
||||||
(void)pubkey_hex_out;
|
|
||||||
(void)relays;
|
|
||||||
(void)relay_count;
|
|
||||||
return NOSTR_ERROR_NETWORK_FAILED; // NIP-05 disabled at compile time
|
|
||||||
}
|
|
||||||
|
|
||||||
int nostr_nip05_lookup(const char* nip05_identifier, char* pubkey_hex_out,
|
|
||||||
char*** relays, int* relay_count, int timeout_seconds) {
|
|
||||||
(void)nip05_identifier;
|
|
||||||
(void)pubkey_hex_out;
|
|
||||||
(void)relays;
|
|
||||||
(void)relay_count;
|
|
||||||
(void)timeout_seconds;
|
|
||||||
return NOSTR_ERROR_NETWORK_FAILED; // NIP-05 disabled at compile time
|
|
||||||
}
|
|
||||||
|
|
||||||
int nostr_nip05_verify(const char* nip05_identifier, const char* pubkey_hex,
|
|
||||||
char*** relays, int* relay_count, int timeout_seconds) {
|
|
||||||
(void)nip05_identifier;
|
|
||||||
(void)pubkey_hex;
|
|
||||||
(void)relays;
|
|
||||||
(void)relay_count;
|
|
||||||
(void)timeout_seconds;
|
|
||||||
return NOSTR_ERROR_NETWORK_FAILED; // NIP-05 disabled at compile time
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DISABLE_NIP05
|
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
#include "nip006.h"
|
#include "nip006.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "nostr_crypto.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key) {
|
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key) {
|
||||||
if (!private_key || !public_key) {
|
if (!private_key || !public_key) {
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nip011.h"
|
#include "nip011.h"
|
||||||
#include "nip005.h" // For HTTP functionality
|
|
||||||
#include "../cjson/cJSON.h"
|
#include "../cjson/cJSON.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
#ifndef DISABLE_NIP05 // NIP-11 uses the same HTTP infrastructure as NIP-05
|
#ifndef DISABLE_NIP05 // NIP-11 uses the same HTTP infrastructure as NIP-05
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count leading zero bits in a hash (NIP-13 reference implementation)
|
* Count leading zero bits in a hash (NIP-13 reference implementation)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
#define BECH32_CONST 1
|
#define BECH32_CONST 1
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,490 @@
|
||||||
|
/*
|
||||||
|
* NIP-44: Encrypted Payloads (Versioned) Implementation
|
||||||
|
* https://github.com/nostr-protocol/nips/blob/master/44.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nip044.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "nostr_common.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "./crypto/nostr_secp256k1.h"
|
||||||
|
|
||||||
|
// Include our ChaCha20 implementation
|
||||||
|
#include "crypto/nostr_chacha20.h"
|
||||||
|
|
||||||
|
// Forward declarations for internal functions
|
||||||
|
static size_t calc_padded_len(size_t unpadded_len);
|
||||||
|
static unsigned char* pad_plaintext(const char* plaintext, size_t* padded_len);
|
||||||
|
static char* unpad_plaintext(const unsigned char* padded, size_t padded_len);
|
||||||
|
static int constant_time_compare(const unsigned char* a, const unsigned char* b, size_t len);
|
||||||
|
|
||||||
|
// Memory clearing utility
|
||||||
|
static void memory_clear(const void *p, size_t len) {
|
||||||
|
if (p && len) {
|
||||||
|
memset((void *)p, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// NIP-44 UTILITY FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Constant-time comparison (security critical)
|
||||||
|
static int constant_time_compare(const unsigned char* a, const unsigned char* b, size_t len) {
|
||||||
|
unsigned char result = 0;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
result |= (a[i] ^ b[i]);
|
||||||
|
}
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIP-44 padding calculation (per spec)
|
||||||
|
static size_t calc_padded_len(size_t unpadded_len) {
|
||||||
|
if (unpadded_len <= 32) {
|
||||||
|
return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t next_power = 1;
|
||||||
|
while (next_power < unpadded_len) {
|
||||||
|
next_power <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t chunk = (next_power <= 256) ? 32 : (next_power / 8);
|
||||||
|
return chunk * ((unpadded_len - 1) / chunk + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIP-44 padding (per spec)
|
||||||
|
static unsigned char* pad_plaintext(const char* plaintext, size_t* padded_len) {
|
||||||
|
size_t unpadded_len = strlen(plaintext);
|
||||||
|
if (unpadded_len > 65535) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIP-44 allows empty messages (unpadded_len can be 0)
|
||||||
|
*padded_len = calc_padded_len(unpadded_len + 2); // +2 for length prefix
|
||||||
|
unsigned char* padded = malloc(*padded_len);
|
||||||
|
if (!padded) return NULL;
|
||||||
|
|
||||||
|
// Write length prefix (big-endian u16)
|
||||||
|
padded[0] = (unpadded_len >> 8) & 0xFF;
|
||||||
|
padded[1] = unpadded_len & 0xFF;
|
||||||
|
|
||||||
|
// Copy plaintext (if any)
|
||||||
|
if (unpadded_len > 0) {
|
||||||
|
memcpy(padded + 2, plaintext, unpadded_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zero-fill padding
|
||||||
|
memset(padded + 2 + unpadded_len, 0, *padded_len - 2 - unpadded_len);
|
||||||
|
|
||||||
|
return padded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NIP-44 unpadding (per spec)
|
||||||
|
static char* unpad_plaintext(const unsigned char* padded, size_t padded_len) {
|
||||||
|
if (padded_len < 2) return NULL;
|
||||||
|
|
||||||
|
// Read length prefix (big-endian u16)
|
||||||
|
size_t unpadded_len = (padded[0] << 8) | padded[1];
|
||||||
|
if (unpadded_len > padded_len - 2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify padding length matches expected
|
||||||
|
size_t expected_padded_len = calc_padded_len(unpadded_len + 2);
|
||||||
|
if (padded_len != expected_padded_len) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* plaintext = malloc(unpadded_len + 1);
|
||||||
|
if (!plaintext) return NULL;
|
||||||
|
|
||||||
|
// Handle empty message case (unpadded_len can be 0)
|
||||||
|
if (unpadded_len > 0) {
|
||||||
|
memcpy(plaintext, padded + 2, unpadded_len);
|
||||||
|
}
|
||||||
|
plaintext[unpadded_len] = '\0';
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// NIP-44 IMPLEMENTATION
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
int nostr_nip44_encrypt_with_nonce(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
const unsigned char* nonce,
|
||||||
|
char* output,
|
||||||
|
size_t output_size) {
|
||||||
|
if (!sender_private_key || !recipient_public_key || !plaintext || !nonce || !output) {
|
||||||
|
return NOSTR_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t plaintext_len = strlen(plaintext);
|
||||||
|
if (plaintext_len > NOSTR_NIP44_MAX_PLAINTEXT_SIZE) {
|
||||||
|
return NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Compute ECDH shared secret
|
||||||
|
unsigned char shared_secret[32];
|
||||||
|
if (ecdh_shared_secret(sender_private_key, recipient_public_key, shared_secret) != 0) {
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Calculate conversation key (HKDF-extract with "nip44-v2" as salt)
|
||||||
|
unsigned char conversation_key[32];
|
||||||
|
const char* salt_str = "nip44-v2";
|
||||||
|
if (nostr_hkdf_extract((const unsigned char*)salt_str, strlen(salt_str),
|
||||||
|
shared_secret, 32, conversation_key) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Use provided nonce (for testing)
|
||||||
|
// Copy nonce for consistency with existing code structure
|
||||||
|
unsigned char nonce_copy[32];
|
||||||
|
memcpy(nonce_copy, nonce, 32);
|
||||||
|
|
||||||
|
// Step 4: Derive message keys (HKDF-expand with nonce as info)
|
||||||
|
unsigned char message_keys[76]; // 32 chacha_key + 12 chacha_nonce + 32 hmac_key
|
||||||
|
if (nostr_hkdf_expand(conversation_key, 32, nonce_copy, 32, message_keys, 76) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce_copy, 32);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* chacha_key = message_keys;
|
||||||
|
unsigned char* chacha_nonce = message_keys + 32;
|
||||||
|
unsigned char* hmac_key = message_keys + 44;
|
||||||
|
|
||||||
|
// Step 5: Pad plaintext according to NIP-44 spec
|
||||||
|
size_t padded_len;
|
||||||
|
unsigned char* padded_plaintext = pad_plaintext(plaintext, &padded_len);
|
||||||
|
if (!padded_plaintext) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6: Encrypt using ChaCha20
|
||||||
|
unsigned char* ciphertext = malloc(padded_len);
|
||||||
|
if (!ciphertext) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chacha20_encrypt(chacha_key, 0, chacha_nonce, padded_plaintext, ciphertext, padded_len) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Compute HMAC with AAD (nonce + ciphertext)
|
||||||
|
unsigned char* aad_data = malloc(32 + padded_len);
|
||||||
|
if (!aad_data) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce_copy, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(aad_data, nonce_copy, 32);
|
||||||
|
memcpy(aad_data + 32, ciphertext, padded_len);
|
||||||
|
|
||||||
|
unsigned char mac[32];
|
||||||
|
if (nostr_hmac_sha256(hmac_key, 32, aad_data, 32 + padded_len, mac) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
memory_clear(aad_data, 32 + padded_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
free(aad_data);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: Format as base64(version + nonce + ciphertext + mac)
|
||||||
|
size_t payload_len = 1 + 32 + padded_len + 32; // version + nonce + ciphertext + mac
|
||||||
|
unsigned char* payload = malloc(payload_len);
|
||||||
|
if (!payload) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
memory_clear(aad_data, 32 + padded_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
free(aad_data);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
payload[0] = 0x02; // NIP-44 version 2
|
||||||
|
memcpy(payload + 1, nonce_copy, 32);
|
||||||
|
memcpy(payload + 33, ciphertext, padded_len);
|
||||||
|
memcpy(payload + 33 + padded_len, mac, 32);
|
||||||
|
|
||||||
|
// Base64 encode
|
||||||
|
size_t b64_len = ((payload_len + 2) / 3) * 4 + 1;
|
||||||
|
if (b64_len > output_size) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
memory_clear(aad_data, 32 + padded_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base64_encode(payload, payload_len, output, output_size) == 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
memory_clear(aad_data, 32 + padded_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(nonce_copy, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(padded_plaintext, padded_len);
|
||||||
|
memory_clear(aad_data, 32 + padded_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(ciphertext);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
|
||||||
|
return NOSTR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nostr_nip44_encrypt(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
char* output,
|
||||||
|
size_t output_size) {
|
||||||
|
// Generate random nonce and call the _with_nonce version
|
||||||
|
unsigned char nonce[32];
|
||||||
|
if (nostr_secp256k1_get_random_bytes(nonce, 32) != 1) {
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nostr_nip44_encrypt_with_nonce(sender_private_key, recipient_public_key,
|
||||||
|
plaintext, nonce, output, output_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nostr_nip44_decrypt(const unsigned char* recipient_private_key,
|
||||||
|
const unsigned char* sender_public_key,
|
||||||
|
const char* encrypted_data,
|
||||||
|
char* output,
|
||||||
|
size_t output_size) {
|
||||||
|
if (!recipient_private_key || !sender_public_key || !encrypted_data || !output) {
|
||||||
|
return NOSTR_ERROR_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 1: Base64 decode the encrypted data
|
||||||
|
size_t max_payload_len = ((strlen(encrypted_data) + 3) / 4) * 3;
|
||||||
|
unsigned char* payload = malloc(max_payload_len);
|
||||||
|
if (!payload) {
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t payload_len = base64_decode(encrypted_data, payload);
|
||||||
|
if (payload_len < 66) { // Minimum: version(1) + nonce(32) + mac(32) + 1 byte ciphertext
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_NIP44_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Extract components (version + nonce + ciphertext + mac)
|
||||||
|
if (payload[0] != 0x02) { // Check NIP-44 version
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_NIP44_INVALID_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* nonce = payload + 1;
|
||||||
|
size_t ciphertext_len = payload_len - 65; // payload - version - nonce - mac
|
||||||
|
unsigned char* ciphertext = payload + 33;
|
||||||
|
unsigned char* received_mac = payload + payload_len - 32;
|
||||||
|
|
||||||
|
// Step 3: Compute ECDH shared secret
|
||||||
|
unsigned char shared_secret[32];
|
||||||
|
if (ecdh_shared_secret(recipient_private_key, sender_public_key, shared_secret) != 0) {
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Calculate conversation key (HKDF-extract with "nip44-v2" as salt)
|
||||||
|
unsigned char conversation_key[32];
|
||||||
|
const char* salt_str = "nip44-v2";
|
||||||
|
if (nostr_hkdf_extract((const unsigned char*)salt_str, strlen(salt_str),
|
||||||
|
shared_secret, 32, conversation_key) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: Derive message keys (HKDF-expand with nonce as info)
|
||||||
|
unsigned char message_keys[76]; // 32 chacha_key + 12 chacha_nonce + 32 hmac_key
|
||||||
|
if (nostr_hkdf_expand(conversation_key, 32, nonce, 32, message_keys, 76) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* chacha_key = message_keys;
|
||||||
|
unsigned char* chacha_nonce = message_keys + 32;
|
||||||
|
unsigned char* hmac_key = message_keys + 44;
|
||||||
|
|
||||||
|
// Step 6: Verify HMAC with AAD (nonce + ciphertext)
|
||||||
|
unsigned char* aad_data = malloc(32 + ciphertext_len);
|
||||||
|
if (!aad_data) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(aad_data, nonce, 32);
|
||||||
|
memcpy(aad_data + 32, ciphertext, ciphertext_len);
|
||||||
|
|
||||||
|
unsigned char computed_mac[32];
|
||||||
|
if (nostr_hmac_sha256(hmac_key, 32, aad_data, 32 + ciphertext_len, computed_mac) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant-time MAC verification
|
||||||
|
if (!constant_time_compare(received_mac, computed_mac, 32)) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_NIP44_DECRYPT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7: Decrypt using ChaCha20
|
||||||
|
unsigned char* padded_plaintext = malloc(ciphertext_len);
|
||||||
|
if (!padded_plaintext) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
return NOSTR_ERROR_MEMORY_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chacha20_encrypt(chacha_key, 0, chacha_nonce, ciphertext, padded_plaintext, ciphertext_len) != 0) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
free(padded_plaintext);
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: Remove padding according to NIP-44 spec
|
||||||
|
char* plaintext = unpad_plaintext(padded_plaintext, ciphertext_len);
|
||||||
|
if (!plaintext) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
memory_clear(padded_plaintext, ciphertext_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
free(padded_plaintext);
|
||||||
|
return NOSTR_ERROR_NIP44_DECRYPT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 9: Copy to output buffer
|
||||||
|
size_t plaintext_len = strlen(plaintext);
|
||||||
|
if (plaintext_len + 1 > output_size) {
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
memory_clear(padded_plaintext, ciphertext_len);
|
||||||
|
memory_clear(plaintext, plaintext_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(plaintext);
|
||||||
|
return NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(output, plaintext);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
memory_clear(shared_secret, 32);
|
||||||
|
memory_clear(conversation_key, 32);
|
||||||
|
memory_clear(message_keys, 76);
|
||||||
|
memory_clear(aad_data, 32 + ciphertext_len);
|
||||||
|
memory_clear(payload, payload_len);
|
||||||
|
memory_clear(padded_plaintext, ciphertext_len);
|
||||||
|
memory_clear(plaintext, plaintext_len);
|
||||||
|
free(aad_data);
|
||||||
|
free(payload);
|
||||||
|
free(padded_plaintext);
|
||||||
|
free(plaintext);
|
||||||
|
|
||||||
|
return NOSTR_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* NIP-44: Encrypted Payloads (Versioned)
|
||||||
|
* https://github.com/nostr-protocol/nips/blob/master/44.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOSTR_NIP044_H
|
||||||
|
#define NOSTR_NIP044_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NIP-44 constants
|
||||||
|
// #define NOSTR_NIP44_MAX_PLAINTEXT_SIZE 65535
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-44: Encrypt a message using ECDH + ChaCha20 + HMAC
|
||||||
|
*
|
||||||
|
* @param sender_private_key 32-byte sender private key
|
||||||
|
* @param recipient_public_key 32-byte recipient public key (x-only)
|
||||||
|
* @param plaintext Message to encrypt
|
||||||
|
* @param output Buffer for encrypted output (base64 encoded)
|
||||||
|
* @param output_size Size of output buffer
|
||||||
|
* @return NOSTR_SUCCESS on success, error code on failure
|
||||||
|
*/
|
||||||
|
int nostr_nip44_encrypt(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
char* output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-44: Encrypt a message with a specific nonce (for testing)
|
||||||
|
*
|
||||||
|
* @param sender_private_key 32-byte sender private key
|
||||||
|
* @param recipient_public_key 32-byte recipient public key (x-only)
|
||||||
|
* @param plaintext Message to encrypt
|
||||||
|
* @param nonce 32-byte nonce
|
||||||
|
* @param output Buffer for encrypted output (base64 encoded)
|
||||||
|
* @param output_size Size of output buffer
|
||||||
|
* @return NOSTR_SUCCESS on success, error code on failure
|
||||||
|
*/
|
||||||
|
int nostr_nip44_encrypt_with_nonce(const unsigned char* sender_private_key,
|
||||||
|
const unsigned char* recipient_public_key,
|
||||||
|
const char* plaintext,
|
||||||
|
const unsigned char* nonce,
|
||||||
|
char* output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NIP-44: Decrypt a message using ECDH + ChaCha20 + HMAC
|
||||||
|
*
|
||||||
|
* @param recipient_private_key 32-byte recipient private key
|
||||||
|
* @param sender_public_key 32-byte sender public key (x-only)
|
||||||
|
* @param encrypted_data Encrypted message (base64 encoded)
|
||||||
|
* @param output Buffer for decrypted plaintext
|
||||||
|
* @param output_size Size of output buffer
|
||||||
|
* @return NOSTR_SUCCESS on success, error code on failure
|
||||||
|
*/
|
||||||
|
int nostr_nip44_decrypt(const unsigned char* recipient_private_key,
|
||||||
|
const unsigned char* sender_public_key,
|
||||||
|
const char* encrypted_data,
|
||||||
|
char* output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NOSTR_NIP044_H
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* NOSTR Core Library - Common Utilities
|
||||||
|
*
|
||||||
|
* Common functions and utilities shared across the library
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nostr_common.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert error code to human-readable string
|
||||||
|
* Handles all error codes defined in nostr_common.h
|
||||||
|
*/
|
||||||
|
const char* nostr_strerror(int error_code) {
|
||||||
|
switch (error_code) {
|
||||||
|
case NOSTR_SUCCESS: return "Success";
|
||||||
|
case NOSTR_ERROR_INVALID_INPUT: return "Invalid input";
|
||||||
|
case NOSTR_ERROR_CRYPTO_FAILED: return "Cryptographic operation failed";
|
||||||
|
case NOSTR_ERROR_MEMORY_FAILED: return "Memory allocation failed";
|
||||||
|
case NOSTR_ERROR_IO_FAILED: return "I/O operation failed";
|
||||||
|
case NOSTR_ERROR_NETWORK_FAILED: return "Network operation failed";
|
||||||
|
case NOSTR_ERROR_NIP04_INVALID_FORMAT: return "NIP-04 invalid format";
|
||||||
|
case NOSTR_ERROR_NIP04_DECRYPT_FAILED: return "NIP-04 decryption failed";
|
||||||
|
case NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL: return "NIP-04 buffer too small";
|
||||||
|
case NOSTR_ERROR_NIP44_INVALID_FORMAT: return "NIP-44: Invalid format";
|
||||||
|
case NOSTR_ERROR_NIP44_DECRYPT_FAILED: return "NIP-44: Decryption failed";
|
||||||
|
case NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL: return "NIP-44: Buffer too small";
|
||||||
|
case NOSTR_ERROR_NIP05_INVALID_IDENTIFIER: return "NIP-05: Invalid identifier format";
|
||||||
|
case NOSTR_ERROR_NIP05_HTTP_FAILED: return "NIP-05: HTTP request failed";
|
||||||
|
case NOSTR_ERROR_NIP05_JSON_PARSE_FAILED: return "NIP-05: JSON parsing failed";
|
||||||
|
case NOSTR_ERROR_NIP05_NAME_NOT_FOUND: return "NIP-05: Name not found in .well-known";
|
||||||
|
case NOSTR_ERROR_NIP05_PUBKEY_MISMATCH: return "NIP-05: Public key mismatch";
|
||||||
|
default: return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the NOSTR library
|
||||||
|
*/
|
||||||
|
int nostr_init(void) {
|
||||||
|
if (nostr_crypto_init() != 0) {
|
||||||
|
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||||
|
}
|
||||||
|
return NOSTR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup the NOSTR library
|
||||||
|
*/
|
||||||
|
void nostr_cleanup(void) {
|
||||||
|
nostr_crypto_cleanup();
|
||||||
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
#define NOSTR_ERROR_NIP05_NAME_NOT_FOUND -19
|
#define NOSTR_ERROR_NIP05_NAME_NOT_FOUND -19
|
||||||
#define NOSTR_ERROR_NIP05_PUBKEY_MISMATCH -20
|
#define NOSTR_ERROR_NIP05_PUBKEY_MISMATCH -20
|
||||||
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
#define NOSTR_PRIVATE_KEY_SIZE 32
|
#define NOSTR_PRIVATE_KEY_SIZE 32
|
||||||
#define NOSTR_PUBLIC_KEY_SIZE 32
|
#define NOSTR_PUBLIC_KEY_SIZE 32
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
#define NOSTR_BECH32_KEY_SIZE 100
|
#define NOSTR_BECH32_KEY_SIZE 100
|
||||||
#define NOSTR_MAX_CONTENT_SIZE 2048
|
#define NOSTR_MAX_CONTENT_SIZE 2048
|
||||||
#define NOSTR_MAX_URL_SIZE 256
|
#define NOSTR_MAX_URL_SIZE 256
|
||||||
|
#define NIP05_DEFAULT_TIMEOUT 10
|
||||||
|
|
||||||
// NIP-04 Constants
|
// NIP-04 Constants
|
||||||
#define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 16777216 // 16MB
|
#define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 16777216 // 16MB
|
||||||
|
@ -43,4 +45,11 @@
|
||||||
// NIP-44 Constants
|
// NIP-44 Constants
|
||||||
#define NOSTR_NIP44_MAX_PLAINTEXT_SIZE 65536 // 64KB max plaintext (matches crypto header)
|
#define NOSTR_NIP44_MAX_PLAINTEXT_SIZE 65536 // 64KB max plaintext (matches crypto header)
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
const char* nostr_strerror(int error_code);
|
||||||
|
|
||||||
|
// Library initialization functions
|
||||||
|
int nostr_init(void);
|
||||||
|
void nostr_cleanup(void);
|
||||||
|
|
||||||
#endif // NOSTR_COMMON_H
|
#endif // NOSTR_COMMON_H
|
||||||
|
|
1374
nostr_core/utils.c
1374
nostr_core/utils.c
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,165 @@
|
||||||
/*
|
/*
|
||||||
* NOSTR Core Library - Utilities
|
* NOSTR Core Library - Utilities
|
||||||
*
|
*
|
||||||
* General utility functions used across multiple NIPs
|
* General utility functions used across multiple NIPs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UTILS_H
|
#ifndef NOSTR_UTILS_H
|
||||||
#define UTILS_H
|
#define NOSTR_UTILS_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// Error codes (imported from nip001.h)
|
#ifdef __cplusplus
|
||||||
#define NOSTR_SUCCESS 0
|
extern "C" {
|
||||||
#define NOSTR_ERROR_INVALID_INPUT -1
|
#endif
|
||||||
|
|
||||||
// Utility function declarations
|
// =============================================================================
|
||||||
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex);
|
// UTILITY FUNCTIONS
|
||||||
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t len);
|
// =============================================================================
|
||||||
|
|
||||||
#endif // UTILS_H
|
// Convert bytes to hexadecimal string
|
||||||
|
void nostr_bytes_to_hex(const unsigned char *bytes, size_t len, char *hex);
|
||||||
|
|
||||||
|
// Convert hexadecimal string to bytes
|
||||||
|
int nostr_hex_to_bytes(const char *hex, unsigned char *bytes, size_t len);
|
||||||
|
|
||||||
|
// Base64 encoding function
|
||||||
|
size_t base64_encode(const unsigned char *data, size_t len, char *output,
|
||||||
|
size_t output_size);
|
||||||
|
|
||||||
|
// Base64 decoding function
|
||||||
|
size_t base64_decode(const char *input, unsigned char *output);
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// CORE CRYPTO FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Initialize crypto subsystem
|
||||||
|
int nostr_crypto_init(void);
|
||||||
|
|
||||||
|
// Cleanup crypto subsystem
|
||||||
|
void nostr_crypto_cleanup(void);
|
||||||
|
|
||||||
|
// SHA-256 hash function
|
||||||
|
int nostr_sha256(const unsigned char *data, size_t len, unsigned char *hash);
|
||||||
|
|
||||||
|
// HMAC-SHA256
|
||||||
|
int nostr_hmac_sha256(const unsigned char *key, size_t key_len,
|
||||||
|
const unsigned char *data, size_t data_len,
|
||||||
|
unsigned char *output);
|
||||||
|
|
||||||
|
// HMAC-SHA512
|
||||||
|
int nostr_hmac_sha512(const unsigned char *key, size_t key_len,
|
||||||
|
const unsigned char *data, size_t data_len,
|
||||||
|
unsigned char *output);
|
||||||
|
|
||||||
|
// PBKDF2 with HMAC-SHA512
|
||||||
|
int nostr_pbkdf2_hmac_sha512(const unsigned char *password, size_t password_len,
|
||||||
|
const unsigned char *salt, size_t salt_len,
|
||||||
|
int iterations, unsigned char *output,
|
||||||
|
size_t output_len);
|
||||||
|
|
||||||
|
// SHA-512 implementation (for testing)
|
||||||
|
int nostr_sha512(const unsigned char *data, size_t len, unsigned char *hash);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// SECP256K1 ELLIPTIC CURVE FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Verify private key is valid
|
||||||
|
int nostr_ec_private_key_verify(const unsigned char *private_key);
|
||||||
|
|
||||||
|
// Generate public key from private key
|
||||||
|
int nostr_ec_public_key_from_private_key(const unsigned char *private_key,
|
||||||
|
unsigned char *public_key);
|
||||||
|
|
||||||
|
// Sign data with ECDSA
|
||||||
|
int nostr_ec_sign(const unsigned char *private_key, const unsigned char *hash,
|
||||||
|
unsigned char *signature);
|
||||||
|
|
||||||
|
// RFC 6979 deterministic nonce generation
|
||||||
|
int nostr_rfc6979_generate_k(const unsigned char *private_key,
|
||||||
|
const unsigned char *message_hash,
|
||||||
|
unsigned char *k_out);
|
||||||
|
|
||||||
|
int nostr_schnorr_sign(const unsigned char* private_key,
|
||||||
|
const unsigned char* hash,
|
||||||
|
unsigned char* signature);
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// HKDF KEY DERIVATION FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// HKDF Extract step
|
||||||
|
int nostr_hkdf_extract(const unsigned char *salt, size_t salt_len,
|
||||||
|
const unsigned char *ikm, size_t ikm_len,
|
||||||
|
unsigned char *prk);
|
||||||
|
|
||||||
|
// HKDF Expand step
|
||||||
|
int nostr_hkdf_expand(const unsigned char *prk, size_t prk_len,
|
||||||
|
const unsigned char *info, size_t info_len,
|
||||||
|
unsigned char *okm, size_t okm_len);
|
||||||
|
|
||||||
|
// HKDF (Extract + Expand)
|
||||||
|
int nostr_hkdf(const unsigned char *salt, size_t salt_len,
|
||||||
|
const unsigned char *ikm, size_t ikm_len,
|
||||||
|
const unsigned char *info, size_t info_len, unsigned char *okm,
|
||||||
|
size_t okm_len);
|
||||||
|
|
||||||
|
// ECDH shared secret computation (for debugging)
|
||||||
|
int ecdh_shared_secret(const unsigned char *private_key,
|
||||||
|
const unsigned char *public_key_x,
|
||||||
|
unsigned char *shared_secret);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// BIP39 MNEMONIC FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Generate mnemonic from entropy
|
||||||
|
int nostr_bip39_mnemonic_from_bytes(const unsigned char *entropy,
|
||||||
|
size_t entropy_len, char *mnemonic);
|
||||||
|
|
||||||
|
// Validate mnemonic
|
||||||
|
int nostr_bip39_mnemonic_validate(const char *mnemonic);
|
||||||
|
|
||||||
|
// Convert mnemonic to seed
|
||||||
|
int nostr_bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase,
|
||||||
|
unsigned char *seed, size_t seed_len);
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// BIP32 HD WALLET FUNCTIONS
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char private_key[32];
|
||||||
|
unsigned char public_key[33];
|
||||||
|
unsigned char chain_code[32];
|
||||||
|
uint32_t depth;
|
||||||
|
uint32_t parent_fingerprint;
|
||||||
|
uint32_t child_number;
|
||||||
|
} nostr_hd_key_t;
|
||||||
|
|
||||||
|
// Create master key from seed
|
||||||
|
int nostr_bip32_key_from_seed(const unsigned char *seed, size_t seed_len,
|
||||||
|
nostr_hd_key_t *master_key);
|
||||||
|
|
||||||
|
// Derive child key from parent
|
||||||
|
int nostr_bip32_derive_child(const nostr_hd_key_t *parent_key,
|
||||||
|
uint32_t child_number, nostr_hd_key_t *child_key);
|
||||||
|
|
||||||
|
// Derive key from path
|
||||||
|
int nostr_bip32_derive_path(const nostr_hd_key_t *master_key,
|
||||||
|
const uint32_t *path, size_t path_len,
|
||||||
|
nostr_hd_key_t *derived_key);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NOSTR_UTILS_H
|
||||||
|
|
BIN
tests/http_test
BIN
tests/http_test
Binary file not shown.
|
@ -9,8 +9,9 @@
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
// Callback to write received data
|
// Callback to write received data
|
||||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, char *userp) {
|
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
|
||||||
size_t realsize = size * nmemb;
|
size_t realsize = size * nmemb;
|
||||||
|
(void)userp; // Mark parameter as deliberately unused
|
||||||
printf("%.*s", (int)realsize, (char*)contents);
|
printf("%.*s", (int)realsize, (char*)contents);
|
||||||
return realsize;
|
return realsize;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +31,7 @@ int main() {
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
|
curl_easy_setopt(curl, CURLOPT_URL, "https://google.com");
|
||||||
|
|
||||||
// Set callback for received data
|
// Set callback for received data
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)WriteCallback);
|
||||||
|
|
||||||
// Follow redirects
|
// Follow redirects
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
|
Binary file not shown.
|
@ -6,7 +6,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../nostr_core/nostr_core.h"
|
#include "../nostr_core/nip004.h"
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
|
|
||||||
void print_hex(const char* label, const unsigned char* data, size_t len) {
|
void print_hex(const char* label, const unsigned char* data, size_t len) {
|
||||||
printf("%s: ", label);
|
printf("%s: ", label);
|
||||||
|
@ -756,10 +758,10 @@ int main(void) {
|
||||||
printf("=== NIP-04 Encryption Test with Reference Test Vectors ===\n\n");
|
printf("=== NIP-04 Encryption Test with Reference Test Vectors ===\n\n");
|
||||||
|
|
||||||
// Initialize the library
|
// Initialize the library
|
||||||
if (nostr_init() != NOSTR_SUCCESS) {
|
// if (nostr_init() != NOSTR_SUCCESS) {
|
||||||
printf("ERROR: Failed to initialize NOSTR library\n");
|
// printf("ERROR: Failed to initialize NOSTR library\n");
|
||||||
return 1;
|
// return 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
int all_passed = 1;
|
int all_passed = 1;
|
||||||
|
|
||||||
|
@ -811,6 +813,6 @@ int main(void) {
|
||||||
printf("❌ SOME TESTS FAILED. Please review the output above.\n");
|
printf("❌ SOME TESTS FAILED. Please review the output above.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
nostr_cleanup();
|
// nostr_cleanup();
|
||||||
return all_passed ? 0 : 1;
|
return all_passed ? 0 : 1;
|
||||||
}
|
}
|
BIN
tests/nip05_test
BIN
tests/nip05_test
Binary file not shown.
|
@ -9,6 +9,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "../nostr_core/nip005.h"
|
#include "../nostr_core/nip005.h"
|
||||||
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
// Test helper function
|
// Test helper function
|
||||||
void print_test_result(const char* test_name, int result) {
|
void print_test_result(const char* test_name, int result) {
|
||||||
|
|
Binary file not shown.
|
@ -7,8 +7,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../nostr_core/nostr_core.h"
|
#include "../nostr_core/nip011.h"
|
||||||
#include "../cjson/cJSON.h"
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
// Test counter
|
// Test counter
|
||||||
static int tests_run = 0;
|
static int tests_run = 0;
|
Binary file not shown.
|
@ -1,348 +0,0 @@
|
||||||
/*
|
|
||||||
* Makefile-Based Static Linking Test
|
|
||||||
*
|
|
||||||
* This test validates static linking configuration by parsing the Makefile
|
|
||||||
* instead of analyzing compiled binaries. This approach is faster, more reliable,
|
|
||||||
* and catches configuration issues at the source.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
// Test result tracking
|
|
||||||
static int tests_run = 0;
|
|
||||||
static int tests_passed = 0;
|
|
||||||
|
|
||||||
// Test macros
|
|
||||||
#define ASSERT(condition, message) \
|
|
||||||
do { \
|
|
||||||
tests_run++; \
|
|
||||||
if (condition) { \
|
|
||||||
printf("✓ %s: PASSED\n", message); \
|
|
||||||
tests_passed++; \
|
|
||||||
} else { \
|
|
||||||
printf("✗ %s: FAILED\n", message); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define ASSERT_CONTAINS(haystack, needle, message) \
|
|
||||||
ASSERT(strstr(haystack, needle) != NULL, message)
|
|
||||||
|
|
||||||
#define ASSERT_NOT_CONTAINS(haystack, needle, message) \
|
|
||||||
ASSERT(strstr(haystack, needle) == NULL, message)
|
|
||||||
|
|
||||||
// File reading utility
|
|
||||||
char* read_file(const char* filename) {
|
|
||||||
FILE* file = fopen(filename, "r");
|
|
||||||
if (!file) {
|
|
||||||
printf("ERROR: Cannot open %s\n", filename);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek(file, 0, SEEK_END);
|
|
||||||
long length = ftell(file);
|
|
||||||
fseek(file, 0, SEEK_SET);
|
|
||||||
|
|
||||||
char* content = malloc(length + 1);
|
|
||||||
if (!content) {
|
|
||||||
fclose(file);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fread(content, 1, length, file);
|
|
||||||
content[length] = '\0';
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract variable value from Makefile
|
|
||||||
char* extract_makefile_variable(const char* content, const char* variable) {
|
|
||||||
char search_pattern[256];
|
|
||||||
snprintf(search_pattern, sizeof(search_pattern), "%s =", variable);
|
|
||||||
|
|
||||||
char* line_start = strstr(content, search_pattern);
|
|
||||||
if (!line_start) {
|
|
||||||
snprintf(search_pattern, sizeof(search_pattern), "%s=", variable);
|
|
||||||
line_start = strstr(content, search_pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!line_start) return NULL;
|
|
||||||
|
|
||||||
// Find start of value (after '=')
|
|
||||||
char* value_start = strchr(line_start, '=');
|
|
||||||
if (!value_start) return NULL;
|
|
||||||
value_start++; // Skip '='
|
|
||||||
|
|
||||||
// Skip whitespace
|
|
||||||
while (*value_start == ' ' || *value_start == '\t') {
|
|
||||||
value_start++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find end of line
|
|
||||||
char* line_end = strchr(value_start, '\n');
|
|
||||||
if (!line_end) {
|
|
||||||
line_end = value_start + strlen(value_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle line continuations with backslash
|
|
||||||
char* result = malloc(2048);
|
|
||||||
char* result_ptr = result;
|
|
||||||
char* current = value_start;
|
|
||||||
|
|
||||||
while (current < line_end) {
|
|
||||||
if (*current == '\\' && (current + 1) < line_end && *(current + 1) == '\n') {
|
|
||||||
// Line continuation - skip to next line
|
|
||||||
current += 2; // Skip '\\\n'
|
|
||||||
// Find next non-whitespace
|
|
||||||
while (current < line_end && (*current == ' ' || *current == '\t')) {
|
|
||||||
current++;
|
|
||||||
}
|
|
||||||
*result_ptr++ = ' '; // Add space between continued lines
|
|
||||||
} else {
|
|
||||||
*result_ptr++ = *current++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*result_ptr = '\0';
|
|
||||||
|
|
||||||
// Trim trailing whitespace
|
|
||||||
result_ptr--;
|
|
||||||
while (result_ptr > result && (*result_ptr == ' ' || *result_ptr == '\t')) {
|
|
||||||
*result_ptr-- = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test static linking configuration
|
|
||||||
void test_static_linking_flags(const char* makefile_content) {
|
|
||||||
printf("\n=== Static Linking Flags Test ===\n");
|
|
||||||
|
|
||||||
// Check TEST_LDFLAGS contains -static
|
|
||||||
char* test_ldflags = extract_makefile_variable(makefile_content, "TEST_LDFLAGS");
|
|
||||||
if (test_ldflags) {
|
|
||||||
ASSERT_CONTAINS(test_ldflags, "-static", "TEST_LDFLAGS contains -static flag");
|
|
||||||
free(test_ldflags);
|
|
||||||
} else {
|
|
||||||
ASSERT(0, "TEST_LDFLAGS variable found in Makefile");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check ARM64_TEST_LDFLAGS contains -static
|
|
||||||
char* arm64_test_ldflags = extract_makefile_variable(makefile_content, "ARM64_TEST_LDFLAGS");
|
|
||||||
if (arm64_test_ldflags) {
|
|
||||||
ASSERT_CONTAINS(arm64_test_ldflags, "-static", "ARM64_TEST_LDFLAGS contains -static flag");
|
|
||||||
free(arm64_test_ldflags);
|
|
||||||
} else {
|
|
||||||
ASSERT(0, "ARM64_TEST_LDFLAGS variable found in Makefile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test forbidden dynamic library links
|
|
||||||
void test_forbidden_dynamic_links(const char* makefile_content) {
|
|
||||||
printf("\n=== Forbidden Dynamic Links Test ===\n");
|
|
||||||
|
|
||||||
// List of libraries that should not be dynamically linked in core tests
|
|
||||||
const char* forbidden_libs[] = {
|
|
||||||
"-lsecp256k1", // Should be statically included
|
|
||||||
"-lsodium", // Not used
|
|
||||||
"-lwally", // Not used
|
|
||||||
"-lmbedtls", // Replaced with OpenSSL
|
|
||||||
"-lmbedx509", // Replaced with OpenSSL
|
|
||||||
"-lmbedcrypto", // Replaced with OpenSSL
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; forbidden_libs[i] != NULL; i++) {
|
|
||||||
// Check that forbidden library is not in TEST_LDFLAGS
|
|
||||||
char* test_ldflags = extract_makefile_variable(makefile_content, "TEST_LDFLAGS");
|
|
||||||
if (test_ldflags) {
|
|
||||||
char message[256];
|
|
||||||
snprintf(message, sizeof(message), "TEST_LDFLAGS does not contain %s", forbidden_libs[i]);
|
|
||||||
ASSERT_NOT_CONTAINS(test_ldflags, forbidden_libs[i], message);
|
|
||||||
free(test_ldflags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that we use the static library
|
|
||||||
void test_static_library_usage(const char* makefile_content) {
|
|
||||||
printf("\n=== Static Library Usage Test ===\n");
|
|
||||||
|
|
||||||
// Check that TEST_LDFLAGS links against our static library
|
|
||||||
char* test_ldflags = extract_makefile_variable(makefile_content, "TEST_LDFLAGS");
|
|
||||||
if (test_ldflags) {
|
|
||||||
ASSERT_CONTAINS(test_ldflags, "-lnostr_core", "TEST_LDFLAGS links against libnostr_core");
|
|
||||||
ASSERT_CONTAINS(test_ldflags, "-lm", "TEST_LDFLAGS links against math library");
|
|
||||||
free(test_ldflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check ARM64 version
|
|
||||||
char* arm64_test_ldflags = extract_makefile_variable(makefile_content, "ARM64_TEST_LDFLAGS");
|
|
||||||
if (arm64_test_ldflags) {
|
|
||||||
ASSERT_CONTAINS(arm64_test_ldflags, "-lnostr_core_arm64", "ARM64_TEST_LDFLAGS links against ARM64 static library");
|
|
||||||
free(arm64_test_ldflags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that compilation flags disable problematic features for static tests only
|
|
||||||
void test_compilation_flags(const char* makefile_content) {
|
|
||||||
printf("\n=== Compilation Flags Test ===\n");
|
|
||||||
|
|
||||||
// Check TEST_CFLAGS contains DISABLE_NIP05 (static tests need to avoid curl)
|
|
||||||
char* test_cflags = extract_makefile_variable(makefile_content, "TEST_CFLAGS");
|
|
||||||
if (test_cflags) {
|
|
||||||
ASSERT_CONTAINS(test_cflags, "-DDISABLE_NIP05", "TEST_CFLAGS disables NIP-05 to avoid curl dependency");
|
|
||||||
free(test_cflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that main compilation does NOT disable NIP05 (NIP-05 should be enabled by default)
|
|
||||||
// Look for DISABLE_NIP05 in object file compilation rules - should NOT be there
|
|
||||||
char* obj_rule_start = strstr(makefile_content, "%.o: %.c");
|
|
||||||
if (obj_rule_start) {
|
|
||||||
char* obj_rule_end = strstr(obj_rule_start, "\n\n");
|
|
||||||
if (!obj_rule_end) obj_rule_end = makefile_content + strlen(makefile_content);
|
|
||||||
|
|
||||||
char* obj_rule = malloc(obj_rule_end - obj_rule_start + 1);
|
|
||||||
strncpy(obj_rule, obj_rule_start, obj_rule_end - obj_rule_start);
|
|
||||||
obj_rule[obj_rule_end - obj_rule_start] = '\0';
|
|
||||||
|
|
||||||
ASSERT_NOT_CONTAINS(obj_rule, "-DDISABLE_NIP05", "Main compilation does not disable NIP-05");
|
|
||||||
free(obj_rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test static curl usage (no dynamic -lcurl)
|
|
||||||
void test_static_curl_usage(const char* makefile_content) {
|
|
||||||
printf("\n=== Static Curl Usage Test ===\n");
|
|
||||||
|
|
||||||
// Count occurrences of -lcurl (should be zero - we use static libcurl.a)
|
|
||||||
int curl_count = 0;
|
|
||||||
const char* search_pos = makefile_content;
|
|
||||||
while ((search_pos = strstr(search_pos, "-lcurl")) != NULL) {
|
|
||||||
curl_count++;
|
|
||||||
search_pos += 6; // Move past "-lcurl"
|
|
||||||
}
|
|
||||||
|
|
||||||
char message[256];
|
|
||||||
snprintf(message, sizeof(message), "No dynamic curl usage found (found %d -lcurl occurrences)", curl_count);
|
|
||||||
ASSERT(curl_count == 0, message);
|
|
||||||
|
|
||||||
// Verify HTTP and NIP-05 tests use static libcurl.a instead
|
|
||||||
ASSERT_CONTAINS(makefile_content, "./curl-install/lib/libcurl.a", "Static libcurl.a is used");
|
|
||||||
|
|
||||||
// Verify curl include path is used
|
|
||||||
ASSERT_CONTAINS(makefile_content, "-I./curl-install/include", "Curl include path is used");
|
|
||||||
|
|
||||||
// Verify both HTTP and NIP-05 tests use static linking
|
|
||||||
char* http_test_line = strstr(makefile_content, "$(HTTP_TEST_EXEC): tests/http_test.c");
|
|
||||||
if (http_test_line) {
|
|
||||||
char* next_rule = strstr(http_test_line, "\n\n");
|
|
||||||
if (!next_rule) next_rule = makefile_content + strlen(makefile_content);
|
|
||||||
|
|
||||||
char* http_section = malloc(next_rule - http_test_line + 1);
|
|
||||||
strncpy(http_section, http_test_line, next_rule - http_test_line);
|
|
||||||
http_section[next_rule - http_test_line] = '\0';
|
|
||||||
|
|
||||||
ASSERT_CONTAINS(http_section, "./curl-install/lib/libcurl.a", "HTTP test uses static libcurl.a");
|
|
||||||
ASSERT_CONTAINS(http_section, "-static", "HTTP test uses static linking");
|
|
||||||
|
|
||||||
free(http_section);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* nip05_test_line = strstr(makefile_content, "$(NIP05_TEST_EXEC): tests/nip05_test.c");
|
|
||||||
if (nip05_test_line) {
|
|
||||||
char* next_rule = strstr(nip05_test_line, "\n\n");
|
|
||||||
if (!next_rule) next_rule = makefile_content + strlen(makefile_content);
|
|
||||||
|
|
||||||
char* nip05_section = malloc(next_rule - nip05_test_line + 1);
|
|
||||||
strncpy(nip05_section, nip05_test_line, next_rule - nip05_test_line);
|
|
||||||
nip05_section[next_rule - nip05_test_line] = '\0';
|
|
||||||
|
|
||||||
ASSERT_CONTAINS(nip05_section, "./curl-install/lib/libcurl.a", "NIP-05 test uses static libcurl.a");
|
|
||||||
ASSERT_CONTAINS(nip05_section, "-static", "NIP-05 test uses static linking");
|
|
||||||
|
|
||||||
free(nip05_section);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that only one Makefile exists
|
|
||||||
void test_single_makefile_policy() {
|
|
||||||
printf("\n=== Single Makefile Policy Test ===\n");
|
|
||||||
|
|
||||||
// Check that subdirectory Makefiles don't exist or are minimal/deprecated
|
|
||||||
int makefile_violations = 0;
|
|
||||||
|
|
||||||
// Check tests/Makefile
|
|
||||||
if (access("tests/Makefile", F_OK) == 0) {
|
|
||||||
char* tests_makefile = read_file("tests/Makefile");
|
|
||||||
if (tests_makefile) {
|
|
||||||
// If tests/Makefile exists and contains actual build rules, it's a violation
|
|
||||||
if (strstr(tests_makefile, "LDFLAGS") || strstr(tests_makefile, "gcc")) {
|
|
||||||
makefile_violations++;
|
|
||||||
printf("WARNING: tests/Makefile contains build rules (should be consolidated)\n");
|
|
||||||
}
|
|
||||||
free(tests_makefile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check nostr_websocket/Makefile
|
|
||||||
if (access("nostr_websocket/Makefile", F_OK) == 0) {
|
|
||||||
char* websocket_makefile = read_file("nostr_websocket/Makefile");
|
|
||||||
if (websocket_makefile) {
|
|
||||||
// If websocket Makefile exists and contains build rules, it's a violation
|
|
||||||
if (strstr(websocket_makefile, "LDFLAGS") || strstr(websocket_makefile, "gcc")) {
|
|
||||||
makefile_violations++;
|
|
||||||
printf("WARNING: nostr_websocket/Makefile contains build rules (should be consolidated)\n");
|
|
||||||
}
|
|
||||||
free(websocket_makefile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char message[256];
|
|
||||||
snprintf(message, sizeof(message), "No Makefile policy violations found (found %d violations)", makefile_violations);
|
|
||||||
ASSERT(makefile_violations == 0, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
printf("Makefile-Based Static Linking Test\n");
|
|
||||||
printf("==================================\n");
|
|
||||||
printf("Testing static linking configuration by parsing Makefile...\n");
|
|
||||||
|
|
||||||
// Read the main Makefile
|
|
||||||
char* makefile_content = read_file("Makefile");
|
|
||||||
if (!makefile_content) {
|
|
||||||
printf("FATAL: Cannot read Makefile\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run all tests
|
|
||||||
test_static_linking_flags(makefile_content);
|
|
||||||
test_forbidden_dynamic_links(makefile_content);
|
|
||||||
test_static_library_usage(makefile_content);
|
|
||||||
test_compilation_flags(makefile_content);
|
|
||||||
test_static_curl_usage(makefile_content);
|
|
||||||
test_single_makefile_policy();
|
|
||||||
|
|
||||||
free(makefile_content);
|
|
||||||
|
|
||||||
// Summary
|
|
||||||
printf("\n============================================\n");
|
|
||||||
printf("TEST SUMMARY\n");
|
|
||||||
printf("============================================\n");
|
|
||||||
printf("Tests run: %d\n", tests_run);
|
|
||||||
printf("Tests passed: %d\n", tests_passed);
|
|
||||||
|
|
||||||
if (tests_passed == tests_run) {
|
|
||||||
printf("ALL TESTS PASSED!\n");
|
|
||||||
printf("✅ Makefile static linking configuration is correct\n");
|
|
||||||
printf("✅ No forbidden dynamic dependencies\n");
|
|
||||||
printf("✅ Single Makefile policy enforced\n");
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
printf("%d TESTS FAILED!\n", tests_run - tests_passed);
|
|
||||||
printf("❌ Makefile configuration needs fixes\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "../nostr_core/nostr_crypto.h"
|
#include "../nostr_core/utils.h"
|
||||||
|
|
||||||
// Helper function to convert hex string to bytes
|
// Helper function to convert hex string to bytes
|
||||||
static void hex_to_bytes(const char* hex, unsigned char* bytes, size_t len) {
|
static void hex_to_bytes(const char* hex, unsigned char* bytes, size_t len) {
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../nostr_core/nip001.h"
|
#include "../nostr_core/nostr_common.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
printf("Testing basic library initialization...\n");
|
printf("Testing basic library initialization...\n");
|
||||||
|
|
Loading…
Reference in New Issue