nostr_core_lib/EXPORTABLE_DESIGN.md

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 API
  • nostr_core.c - Implementation
  • nostr_crypto.h - Crypto API
  • nostr_crypto.c - Self-contained crypto
  • cjson/ directory - JSON parsing

Optional Files:

  • nostr_websocket/ - WebSocket relay support
  • mbedtls/ - Enhanced crypto backend
  • examples/ - Usage examples
  • tests/ - 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:

  1. Report compatibility issues
  2. Submit test vectors from their use cases
  3. Contribute performance improvements
  4. 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.