8.2 KiB
Exportable C NOSTR Library Design Guide
This document outlines the design principles and structure for making the C NOSTR library easily exportable and reusable across multiple projects.
Overview
The C NOSTR library is designed as a modular, self-contained implementation that can be easily integrated into other projects while maintaining compatibility with the broader NOSTR ecosystem.
Design Principles
1. Modular Architecture
- Core Layer: Essential NOSTR functionality (
nostr_core.c/h
) - Crypto Layer: Self-contained cryptographic primitives (
nostr_crypto.c/h
) - WebSocket Layer: Optional networking functionality (
nostr_websocket/
) - Dependencies: Minimal external dependencies (only cJSON and mbedTLS)
2. Clean API Surface
- Consistent function naming with
nostr_
prefix - Clear return codes using
NOSTR_SUCCESS
/NOSTR_ERROR_*
constants - Well-documented function signatures
- No global state where possible
3. Self-Contained Crypto
- Custom implementations of SHA-256, HMAC, secp256k1
- BIP39 wordlist embedded in code
- No external crypto library dependencies for core functionality
- Optional mbedTLS integration for enhanced security
4. Cross-Platform Compatibility
- Standard C99 code
- Platform-specific code isolated in separate modules
- ARM64 and x86_64 tested builds
- Static library compilation support
Library Structure
c_nostr/
├── nostr_core.h # High-level API
├── nostr_core.c # Implementation
├── nostr_crypto.h # Crypto primitives API
├── nostr_crypto.c # Self-contained crypto
├── libnostr_core.a # Static library (x86_64)
├── libnostr_core.so # Shared library (x86_64)
├── cjson/ # JSON parsing (vendored)
├── mbedtls/ # Optional crypto backend
├── examples/ # Usage examples
├── tests/ # Test suites
└── nostr_websocket/ # Optional WebSocket layer
Integration Methods
Method 1: Static Library Linking
Best for: Applications that want a single binary with all NOSTR functionality embedded.
# Build the library
make lib
# In your project Makefile:
CFLAGS += -I/path/to/c_nostr
LDFLAGS += -L/path/to/c_nostr -lnostr_core -lm -static
Usage:
#include "nostr_core.h"
int main() {
if (nostr_init() != NOSTR_SUCCESS) {
return 1;
}
unsigned char private_key[32], public_key[32];
nostr_generate_keypair(private_key, public_key);
cJSON* event = nostr_create_text_event("Hello NOSTR!", private_key);
// ... use event
nostr_cleanup();
return 0;
}
Method 2: Source Code Integration
Best for: Applications that want to customize the crypto backend or minimize dependencies.
# Copy essential files to your project:
cp nostr_core.{c,h} your_project/src/
cp nostr_crypto.{c,h} your_project/src/
cp -r cjson/ your_project/src/
Compile with your project:
// In your source
#include "nostr_core.h"
// Use NOSTR functions directly
Method 3: Git Submodule
Best for: Projects that want to track upstream changes and contribute back.
# In your project root:
git submodule add https://github.com/yourorg/c_nostr.git deps/c_nostr
git submodule update --init --recursive
# In your Makefile:
CFLAGS += -Ideps/c_nostr
LDFLAGS += -Ldeps/c_nostr -lnostr_core
Method 4: Shared Library
Best for: System-wide installation or multiple applications sharing the same NOSTR implementation.
# Install system-wide
sudo make install
# In your project:
CFLAGS += $(pkg-config --cflags nostr_core)
LDFLAGS += $(pkg-config --libs nostr_core)
API Design for Exportability
Consistent Error Handling
typedef enum {
NOSTR_SUCCESS = 0,
NOSTR_ERROR_INVALID_INPUT = -1,
NOSTR_ERROR_CRYPTO_FAILED = -2,
NOSTR_ERROR_MEMORY_ALLOCATION = -3,
NOSTR_ERROR_JSON_PARSE = -4,
NOSTR_ERROR_NETWORK = -5
} nostr_error_t;
const char* nostr_strerror(int error_code);
Clean Resource Management
// Always provide cleanup functions
int nostr_init(void);
void nostr_cleanup(void);
// JSON objects returned should be freed by caller
cJSON* nostr_create_text_event(const char* content, const unsigned char* private_key);
// Caller must call cJSON_Delete(event) when done
Optional Features
// Compile-time feature toggles
#ifndef NOSTR_DISABLE_WEBSOCKETS
int nostr_connect_relay(const char* url);
#endif
#ifndef NOSTR_DISABLE_IDENTITY_PERSISTENCE
int nostr_save_identity(const unsigned char* private_key, const char* password, int account);
#endif
Configuration System
Build-Time Configuration
// nostr_config.h (generated during build)
#define NOSTR_VERSION "1.0.0"
#define NOSTR_HAS_MBEDTLS 1
#define NOSTR_HAS_WEBSOCKETS 1
#define NOSTR_STATIC_BUILD 1
Runtime Configuration
typedef struct {
int log_level;
char* identity_file_path;
int default_account;
int enable_networking;
} nostr_config_t;
int nostr_set_config(const nostr_config_t* config);
const nostr_config_t* nostr_get_config(void);
Testing and Validation
Ecosystem Compatibility Testing
The library includes comprehensive test suites that validate compatibility with reference implementations like nak
:
# Run all tests
cd tests && make test
# Test specific functionality
make test-crypto # Cryptographic primitives
make test-core # High-level NOSTR functions
Test Vectors
Real-world test vectors are generated using nak
to ensure ecosystem compatibility:
- Key generation and derivation (BIP39/BIP32)
- Event creation and signing
- Bech32 encoding/decoding
- Message serialization
Documentation for Exporters
Essential Files Checklist
For projects integrating this library, you need:
Core Files (Required):
nostr_core.h
- Main APInostr_core.c
- Implementationnostr_crypto.h
- Crypto APInostr_crypto.c
- Self-contained cryptocjson/
directory - JSON parsing
Optional Files:
nostr_websocket/
- WebSocket relay supportmbedtls/
- Enhanced crypto backendexamples/
- Usage examplestests/
- Validation tests
Minimal Integration Example
// minimal_nostr.c - Smallest possible integration
#include "nostr_core.h"
int main() {
// Initialize library
nostr_init();
// Generate keypair
unsigned char priv[32], pub[32];
nostr_generate_keypair(priv, pub);
// Create and sign event
cJSON* event = nostr_create_text_event("Hello from my app!", priv);
char* json_string = cJSON_Print(event);
printf("Event: %s\n", json_string);
// Cleanup
free(json_string);
cJSON_Delete(event);
nostr_cleanup();
return 0;
}
Compile:
gcc -I. minimal_nostr.c nostr_core.c nostr_crypto.c cjson/cJSON.c -lm -o minimal_nostr
Future Considerations
Language Bindings
The C library is designed to be easily wrapped:
- Python: Use ctypes or cffi
- JavaScript: Use Node.js FFI or WASM compilation
- Go: Use cgo
- Rust: Use bindgen for FFI bindings
WebAssembly Support
The library can be compiled to WebAssembly for browser usage:
emcc -O3 -s WASM=1 -s EXPORTED_FUNCTIONS='["_nostr_init", "_nostr_generate_keypair"]' \
nostr_core.c nostr_crypto.c cjson/cJSON.c -o nostr.wasm
Package Manager Support
Future versions may include:
- pkgconfig files for system installation
- CMake integration for easier builds
- vcpkg/Conan package definitions
Contributing Back
Projects using this library are encouraged to:
- Report compatibility issues
- Submit test vectors from their use cases
- Contribute performance improvements
- Add support for additional NIPs
Version Compatibility
The library follows semantic versioning:
- Major: Breaking API changes
- Minor: New features, backward compatible
- Patch: Bug fixes
API stability guarantees:
- All functions prefixed with
nostr_
are part of the stable API - Internal functions (static or prefixed with
_
) may change - Configuration structures may be extended but not modified
This design ensures the C NOSTR library can be easily adopted by other projects while maintaining high compatibility with the NOSTR ecosystem standards.