remove exposed .h crypto headers
This commit is contained in:
@@ -1,15 +1,76 @@
|
||||
/*
|
||||
* NOSTR AES Implementation
|
||||
*
|
||||
*
|
||||
* Based on tiny-AES-c by kokke (public domain)
|
||||
* Configured specifically for NIP-04: AES-256-CBC only
|
||||
*
|
||||
*
|
||||
* This is an implementation of the AES algorithm, specifically CBC mode.
|
||||
* Configured for AES-256 as required by NIP-04.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h> // CBC mode, for memset
|
||||
#include "nostr_aes.h"
|
||||
|
||||
// Configure for NIP-04 requirements: AES-256-CBC only
|
||||
#define CBC 1
|
||||
#define ECB 0
|
||||
#define CTR 0
|
||||
|
||||
// Configure for AES-256 (required by NIP-04)
|
||||
#define AES128 0
|
||||
#define AES192 0
|
||||
#define AES256 1
|
||||
|
||||
#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define AES_KEYLEN 32
|
||||
#define AES_keyExpSize 240
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define AES_KEYLEN 24
|
||||
#define AES_keyExpSize 208
|
||||
#else
|
||||
#define AES_KEYLEN 16 // Key length in bytes
|
||||
#define AES_keyExpSize 176
|
||||
#endif
|
||||
|
||||
struct AES_ctx
|
||||
{
|
||||
uint8_t RoundKey[AES_keyExpSize];
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
uint8_t Iv[AES_BLOCKLEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
// state - array holding the intermediate results during decryption.
|
||||
typedef uint8_t state_t[4][4];
|
||||
|
||||
// Function prototypes (internal use only)
|
||||
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key);
|
||||
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey);
|
||||
static void SubBytes(state_t* state);
|
||||
static void ShiftRows(state_t* state);
|
||||
static uint8_t xtime(uint8_t x);
|
||||
static void MixColumns(state_t* state);
|
||||
static void InvMixColumns(state_t* state);
|
||||
static void InvSubBytes(state_t* state);
|
||||
static void InvShiftRows(state_t* state);
|
||||
static void Cipher(state_t* state, const uint8_t* RoundKey);
|
||||
static void InvCipher(state_t* state, const uint8_t* RoundKey);
|
||||
static void XorWithIv(uint8_t* buf, const uint8_t* Iv);
|
||||
|
||||
// Public functions (used by NIP-04 implementation)
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||
#endif
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
#endif
|
||||
|
||||
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||
#define Nb 4
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#ifndef _NOSTR_AES_H_
|
||||
#define _NOSTR_AES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Configure for NIP-04 requirements: AES-256-CBC only
|
||||
#define CBC 1
|
||||
#define ECB 0
|
||||
#define CTR 0
|
||||
|
||||
// Configure for AES-256 (required by NIP-04)
|
||||
#define AES128 0
|
||||
#define AES192 0
|
||||
#define AES256 1
|
||||
|
||||
#define AES_BLOCKLEN 16 // Block length in bytes - AES is 128b block only
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define AES_KEYLEN 32
|
||||
#define AES_keyExpSize 240
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define AES_KEYLEN 24
|
||||
#define AES_keyExpSize 208
|
||||
#else
|
||||
#define AES_KEYLEN 16 // Key length in bytes
|
||||
#define AES_keyExpSize 176
|
||||
#endif
|
||||
|
||||
struct AES_ctx
|
||||
{
|
||||
uint8_t RoundKey[AES_keyExpSize];
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
uint8_t Iv[AES_BLOCKLEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||
#endif
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
// buffer size MUST be multiple of AES_BLOCKLEN;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||
#endif // #if defined(CBC) && (CBC == 1)
|
||||
|
||||
#endif // _NOSTR_AES_H_
|
||||
@@ -1,15 +1,47 @@
|
||||
/*
|
||||
* nostr_chacha20.c - ChaCha20 stream cipher implementation
|
||||
*
|
||||
*
|
||||
* Implementation based on RFC 8439 "ChaCha20 and Poly1305 for IETF Protocols"
|
||||
*
|
||||
*
|
||||
* This implementation is adapted from the RFC 8439 reference specification.
|
||||
* It prioritizes correctness and clarity over performance optimization.
|
||||
*/
|
||||
|
||||
#include "nostr_chacha20.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* CONSTANTS AND DEFINITIONS
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
#define CHACHA20_KEY_SIZE 32 /* 256 bits */
|
||||
#define CHACHA20_NONCE_SIZE 12 /* 96 bits */
|
||||
#define CHACHA20_BLOCK_SIZE 64 /* 512 bits */
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* FUNCTION PROTOTYPES (INTERNAL USE ONLY)
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
// Internal utility functions
|
||||
static uint32_t bytes_to_u32_le(const uint8_t *bytes);
|
||||
static void u32_to_bytes_le(uint32_t val, uint8_t *bytes);
|
||||
|
||||
// Public functions (used by NIP-44 implementation)
|
||||
void chacha20_quarter_round(uint32_t state[16], int a, int b, int c, int d);
|
||||
int chacha20_block(const uint8_t key[32], uint32_t counter,
|
||||
const uint8_t nonce[12], uint8_t output[64]);
|
||||
int chacha20_encrypt(const uint8_t key[32], uint32_t counter,
|
||||
const uint8_t nonce[12], const uint8_t* input,
|
||||
uint8_t* output, size_t length);
|
||||
void chacha20_init_state(uint32_t state[16], const uint8_t key[32],
|
||||
uint32_t counter, const uint8_t nonce[12]);
|
||||
void chacha20_serialize_state(const uint32_t state[16], uint8_t output[64]);
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* UTILITY MACROS AND FUNCTIONS
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* nostr_chacha20.h - ChaCha20 stream cipher implementation
|
||||
*
|
||||
* Implementation based on RFC 8439 "ChaCha20 and Poly1305 for IETF Protocols"
|
||||
*
|
||||
* This is a small, portable implementation for NIP-44 support in the NOSTR library.
|
||||
* The implementation prioritizes correctness and simplicity over performance.
|
||||
*/
|
||||
|
||||
#ifndef NOSTR_CHACHA20_H
|
||||
#define NOSTR_CHACHA20_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* CONSTANTS AND DEFINITIONS
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
#define CHACHA20_KEY_SIZE 32 /* 256 bits */
|
||||
#define CHACHA20_NONCE_SIZE 12 /* 96 bits */
|
||||
#define CHACHA20_BLOCK_SIZE 64 /* 512 bits */
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* CORE CHACHA20 FUNCTIONS
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* ChaCha20 quarter round operation
|
||||
*
|
||||
* Operates on four 32-bit words performing the core ChaCha20 quarter round:
|
||||
* a += b; d ^= a; d <<<= 16;
|
||||
* c += d; b ^= c; b <<<= 12;
|
||||
* a += b; d ^= a; d <<<= 8;
|
||||
* c += d; b ^= c; b <<<= 7;
|
||||
*
|
||||
* @param state[in,out] ChaCha state as 16 32-bit words
|
||||
* @param a, b, c, d Indices into state array for quarter round
|
||||
*/
|
||||
void chacha20_quarter_round(uint32_t state[16], int a, int b, int c, int d);
|
||||
|
||||
/**
|
||||
* ChaCha20 block function
|
||||
*
|
||||
* Transforms a 64-byte input block using ChaCha20 algorithm with 20 rounds.
|
||||
*
|
||||
* @param key[in] 32-byte key
|
||||
* @param counter[in] 32-bit block counter
|
||||
* @param nonce[in] 12-byte nonce
|
||||
* @param output[out] 64-byte output buffer
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int chacha20_block(const uint8_t key[32], uint32_t counter,
|
||||
const uint8_t nonce[12], uint8_t output[64]);
|
||||
|
||||
/**
|
||||
* ChaCha20 encryption/decryption
|
||||
*
|
||||
* Encrypts or decrypts data using ChaCha20 stream cipher.
|
||||
* Since ChaCha20 is a stream cipher, encryption and decryption are the same operation.
|
||||
*
|
||||
* @param key[in] 32-byte key
|
||||
* @param counter[in] Initial 32-bit counter value
|
||||
* @param nonce[in] 12-byte nonce
|
||||
* @param input[in] Input data to encrypt/decrypt
|
||||
* @param output[out] Output buffer (can be same as input)
|
||||
* @param length[in] Length of input data in bytes
|
||||
* @return 0 on success, negative on error
|
||||
*/
|
||||
int chacha20_encrypt(const uint8_t key[32], uint32_t counter,
|
||||
const uint8_t nonce[12], const uint8_t* input,
|
||||
uint8_t* output, size_t length);
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* UTILITY FUNCTIONS
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize ChaCha20 state matrix
|
||||
*
|
||||
* Sets up the initial 16-word state matrix with constants, key, counter, and nonce.
|
||||
*
|
||||
* @param state[out] 16-word state array to initialize
|
||||
* @param key[in] 32-byte key
|
||||
* @param counter[in] 32-bit block counter
|
||||
* @param nonce[in] 12-byte nonce
|
||||
*/
|
||||
void chacha20_init_state(uint32_t state[16], const uint8_t key[32],
|
||||
uint32_t counter, const uint8_t nonce[12]);
|
||||
|
||||
/**
|
||||
* Serialize ChaCha20 state to bytes
|
||||
*
|
||||
* Converts 16 32-bit words to 64 bytes in little-endian format.
|
||||
*
|
||||
* @param state[in] 16-word state array
|
||||
* @param output[out] 64-byte output buffer
|
||||
*/
|
||||
void chacha20_serialize_state(const uint32_t state[16], uint8_t output[64]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NOSTR_CHACHA20_H */
|
||||
@@ -1,4 +1,3 @@
|
||||
#include "nostr_secp256k1.h"
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
@@ -6,6 +5,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* PRIVATE INTERNAL FUNCTIONS - NOT EXPORTED
|
||||
* These functions are for internal library use only.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a parsed keypair.
|
||||
* Guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} nostr_secp256k1_keypair;
|
||||
|
||||
/** Opaque data structure that holds a parsed x-only public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_xonly_pubkey;
|
||||
|
||||
// Global context for secp256k1 operations
|
||||
static secp256k1_context* g_ctx = NULL;
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
#ifndef NOSTR_SECP256K1_H
|
||||
#define NOSTR_SECP256K1_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a parsed keypair.
|
||||
* Guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} nostr_secp256k1_keypair;
|
||||
|
||||
/** Opaque data structure that holds a parsed x-only public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_xonly_pubkey;
|
||||
|
||||
/** Initialize the secp256k1 library. Must be called before any other functions.
|
||||
* Returns: 1 on success, 0 on failure.
|
||||
*/
|
||||
int nostr_secp256k1_context_create(void);
|
||||
|
||||
/** Clean up the secp256k1 library resources.
|
||||
*/
|
||||
void nostr_secp256k1_context_destroy(void);
|
||||
|
||||
/** Verify an elliptic curve secret key.
|
||||
* Returns: 1: secret key is valid, 0: secret key is invalid
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
int nostr_secp256k1_ec_seckey_verify(const unsigned char *seckey);
|
||||
|
||||
/** Compute the public key for a secret key.
|
||||
* Returns: 1: secret was valid, public key stored. 0: secret was invalid.
|
||||
* Out: pubkey: pointer to the created public key.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
int nostr_secp256k1_ec_pubkey_create(nostr_secp256k1_pubkey *pubkey, const unsigned char *seckey);
|
||||
|
||||
/** Create a keypair from a secret key.
|
||||
* Returns: 1: keypair created, 0: secret key invalid.
|
||||
* Out: keypair: pointer to the created keypair.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
int nostr_secp256k1_keypair_create(nostr_secp256k1_keypair *keypair, const unsigned char *seckey);
|
||||
|
||||
/** Get the x-only public key from a keypair.
|
||||
* Returns: 1 always.
|
||||
* Out: pubkey: pointer to storage for the x-only public key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
int nostr_secp256k1_keypair_xonly_pub(nostr_secp256k1_xonly_pubkey *pubkey, const nostr_secp256k1_keypair *keypair);
|
||||
|
||||
/** Parse an x-only public key from bytes.
|
||||
* Returns: 1: public key parsed, 0: invalid public key.
|
||||
* Out: pubkey: pointer to the created x-only public key.
|
||||
* In: input32: pointer to a 32-byte x-only public key.
|
||||
*/
|
||||
int nostr_secp256k1_xonly_pubkey_parse(nostr_secp256k1_xonly_pubkey *pubkey, const unsigned char *input32);
|
||||
|
||||
/** Serialize an x-only public key to bytes.
|
||||
* Returns: 1 always.
|
||||
* Out: output32: pointer to a 32-byte array to store the serialized key.
|
||||
* In: pubkey: pointer to an x-only public key.
|
||||
*/
|
||||
int nostr_secp256k1_xonly_pubkey_serialize(unsigned char *output32, const nostr_secp256k1_xonly_pubkey *pubkey);
|
||||
|
||||
/** Create a Schnorr signature.
|
||||
* Returns: 1: signature created, 0: nonce generation failed or secret key invalid.
|
||||
* Out: sig64: pointer to a 64-byte array where the signature will be placed.
|
||||
* In: msghash32: the 32-byte message hash being signed.
|
||||
* keypair: pointer to an initialized keypair.
|
||||
* aux_rand32: pointer to 32 bytes of auxiliary randomness (can be NULL).
|
||||
*/
|
||||
int nostr_secp256k1_schnorrsig_sign32(unsigned char *sig64, const unsigned char *msghash32, const nostr_secp256k1_keypair *keypair, const unsigned char *aux_rand32);
|
||||
|
||||
/** Verify a Schnorr signature.
|
||||
* Returns: 1: correct signature, 0: incorrect signature
|
||||
* In: sig64: pointer to the 64-byte signature being verified.
|
||||
* msghash32: the 32-byte message hash being verified.
|
||||
* pubkey: pointer to an x-only public key to verify with.
|
||||
*/
|
||||
int nostr_secp256k1_schnorrsig_verify(const unsigned char *sig64, const unsigned char *msghash32, const nostr_secp256k1_xonly_pubkey *pubkey);
|
||||
|
||||
/** Serialize a pubkey object into a serialized byte sequence.
|
||||
* Returns: 1 always.
|
||||
* Out: output: pointer to a 33-byte array to place the serialized key in.
|
||||
* In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key.
|
||||
*
|
||||
* The output will be a 33-byte compressed public key (0x02 or 0x03 prefix + 32 bytes x coordinate).
|
||||
*/
|
||||
int nostr_secp256k1_ec_pubkey_serialize_compressed(unsigned char *output, const nostr_secp256k1_pubkey *pubkey);
|
||||
|
||||
/** Tweak a secret key by adding a 32-byte tweak to it.
|
||||
* Returns: 1: seckey was valid, 0: seckey invalid or resulting key invalid
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. Will be modified in-place.
|
||||
* In: tweak: pointer to a 32-byte tweak.
|
||||
*/
|
||||
int nostr_secp256k1_ec_seckey_tweak_add(unsigned char *seckey, const unsigned char *tweak);
|
||||
|
||||
/** Parse a variable-length public key into the pubkey object.
|
||||
* Returns: 1: public key parsed, 0: invalid public key.
|
||||
* Out: pubkey: pointer to the created public key.
|
||||
* In: input: pointer to a serialized public key
|
||||
* inputlen: length of the array pointed to by input
|
||||
*/
|
||||
int nostr_secp256k1_ec_pubkey_parse(nostr_secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen);
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time.
|
||||
* Returns: 1: exponentiation was successful, 0: scalar was invalid (zero or overflow)
|
||||
* Out: result: a 32-byte array which will be populated by an ECDH secret computed from point and scalar
|
||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an initialized public key
|
||||
* seckey: a 32-byte scalar with which to multiply the point
|
||||
*/
|
||||
int nostr_secp256k1_ecdh(unsigned char *result, const nostr_secp256k1_pubkey *pubkey, const unsigned char *seckey, void *hashfp, void *data);
|
||||
|
||||
/** Generate cryptographically secure random bytes.
|
||||
* Returns: 1: success, 0: failure
|
||||
* Out: buf: buffer to fill with random bytes
|
||||
* In: len: number of bytes to generate
|
||||
*/
|
||||
int nostr_secp256k1_get_random_bytes(unsigned char *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NOSTR_SECP256K1_H */
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "nip001.h"
|
||||
#include "utils.h"
|
||||
#include "crypto/nostr_secp256k1.h"
|
||||
#include "../cjson/cJSON.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -14,9 +13,21 @@
|
||||
#include <time.h>
|
||||
#include "../nostr_core/nostr_common.h"
|
||||
|
||||
// Forward declarations for crypto functions (private API)
|
||||
// These functions are implemented in crypto/ but not exposed through public headers
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_xonly_pubkey;
|
||||
|
||||
int nostr_secp256k1_xonly_pubkey_parse(nostr_secp256k1_xonly_pubkey* pubkey, const unsigned char* input32);
|
||||
int nostr_secp256k1_schnorrsig_verify(const unsigned char* sig64, const unsigned char* msg32, const nostr_secp256k1_xonly_pubkey* pubkey);
|
||||
|
||||
// Declare utility functions
|
||||
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_sha256(const unsigned char* data, size_t len, unsigned char* hash);
|
||||
int nostr_ec_public_key_from_private_key(const unsigned char* private_key, unsigned char* public_key);
|
||||
int nostr_ec_sign(const unsigned char* private_key, const unsigned char* hash, unsigned char* signature);
|
||||
|
||||
/**
|
||||
* Create and sign a NOSTR event
|
||||
|
||||
@@ -6,13 +6,24 @@
|
||||
#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 crypto functions (private API)
|
||||
// These functions are implemented in crypto/ but not exposed through public headers
|
||||
int ecdh_shared_secret(const unsigned char* private_key, const unsigned char* public_key, unsigned char* shared_secret);
|
||||
int nostr_secp256k1_get_random_bytes(unsigned char* buf, size_t len);
|
||||
|
||||
// AES context and functions for NIP-04 encryption
|
||||
struct AES_ctx {
|
||||
unsigned char RoundKey[240]; // AES-256 key expansion
|
||||
unsigned char Iv[16]; // Initialization vector
|
||||
};
|
||||
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const unsigned char* key, const unsigned char* iv);
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, unsigned char* buf, size_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, unsigned char* buf, size_t length);
|
||||
|
||||
// Forward declarations for internal functions
|
||||
static int aes_cbc_encrypt(const unsigned char* key, const unsigned char* iv,
|
||||
|
||||
@@ -9,10 +9,29 @@
|
||||
#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 crypto functions (private API)
|
||||
// These functions are implemented in crypto/ but not exposed through public headers
|
||||
int ecdh_shared_secret(const unsigned char* private_key, const unsigned char* public_key, unsigned char* shared_secret);
|
||||
int nostr_secp256k1_get_random_bytes(unsigned char* buf, size_t len);
|
||||
|
||||
// ChaCha20 functions for NIP-44 encryption
|
||||
int chacha20_encrypt(const unsigned char key[32], unsigned int counter,
|
||||
const unsigned char nonce[12], const unsigned char* input,
|
||||
unsigned char* output, size_t length);
|
||||
|
||||
// HKDF functions for NIP-44 key derivation
|
||||
int nostr_hkdf_extract(const unsigned char* salt, size_t salt_len,
|
||||
const unsigned char* ikm, size_t ikm_len,
|
||||
unsigned char* prk);
|
||||
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);
|
||||
|
||||
// HMAC-SHA256 function for NIP-44 authentication
|
||||
int nostr_hmac_sha256(const unsigned char* key, size_t key_len,
|
||||
const unsigned char* data, size_t data_len,
|
||||
unsigned char* hmac);
|
||||
|
||||
// Forward declarations for internal functions
|
||||
static size_t calc_padded_len(size_t unpadded_len);
|
||||
|
||||
@@ -1,11 +1,103 @@
|
||||
#ifndef NOSTR_CORE_H
|
||||
#define NOSTR_CORE_H
|
||||
|
||||
/**
|
||||
* NOSTR Core Library - Unified Header File
|
||||
/*
|
||||
* NOSTR Core Library - Complete API Reference
|
||||
*
|
||||
* This file provides a single include point for all NOSTR Core functionality.
|
||||
* Include this file to access all available NIPs and core functions.
|
||||
* This header includes ALL library functionality. For modular includes,
|
||||
* use individual headers instead.
|
||||
*
|
||||
* ============================================================================
|
||||
* QUICK FUNCTION REFERENCE - Find what you need fast!
|
||||
* ============================================================================
|
||||
*
|
||||
* EVENT OPERATIONS (NIP-01):
|
||||
* - nostr_create_and_sign_event() -> Create and sign new Nostr events
|
||||
* - nostr_validate_event() -> Validate complete Nostr event
|
||||
* - nostr_validate_event_structure() -> Check event structure only
|
||||
* - nostr_verify_event_signature() -> Verify cryptographic signature
|
||||
*
|
||||
* CRYPTOGRAPHIC HASHING:
|
||||
* - nostr_sha256() -> Single-call SHA-256 hash
|
||||
* - nostr_sha256_init() -> Initialize streaming SHA-256 context
|
||||
* - nostr_sha256_update() -> Process data chunks incrementally
|
||||
* - nostr_sha256_final() -> Finalize hash and clear context
|
||||
* - nostr_sha256_file_stream() -> Hash large files efficiently (NEW!)
|
||||
* - nostr_sha512() -> SHA-512 hash function
|
||||
* - nostr_hmac_sha256() -> HMAC with SHA-256
|
||||
* - nostr_hmac_sha512() -> HMAC with SHA-512
|
||||
*
|
||||
* DIGITAL SIGNATURES & KEYS:
|
||||
* - nostr_schnorr_sign() -> Create Schnorr signatures
|
||||
* - nostr_ec_public_key_from_private_key() -> Generate public keys
|
||||
* - nostr_ec_private_key_verify() -> Validate private key format
|
||||
* - nostr_ec_sign() -> ECDSA signature creation
|
||||
* - nostr_rfc6979_generate_k() -> Deterministic nonce generation
|
||||
*
|
||||
* NIP-04 ENCRYPTION (Legacy):
|
||||
* - nostr_nip04_encrypt() -> Encrypt messages (AES-256-CBC)
|
||||
* - nostr_nip04_decrypt() -> Decrypt messages (AES-256-CBC)
|
||||
*
|
||||
* NIP-44 ENCRYPTION (Modern - Recommended):
|
||||
* - nostr_nip44_encrypt() -> Encrypt with ChaCha20 + HMAC
|
||||
* - nostr_nip44_encrypt_with_nonce() -> Encrypt with specific nonce (testing)
|
||||
* - nostr_nip44_decrypt() -> Decrypt ChaCha20 + HMAC messages
|
||||
*
|
||||
* BIP39 MNEMONICS:
|
||||
* - nostr_bip39_mnemonic_from_bytes() -> Generate mnemonic from entropy
|
||||
* - nostr_bip39_mnemonic_validate() -> Validate mnemonic phrase
|
||||
* - nostr_bip39_mnemonic_to_seed() -> Convert mnemonic to seed
|
||||
*
|
||||
* BIP32 HD WALLETS:
|
||||
* - nostr_bip32_key_from_seed() -> Create master key from seed
|
||||
* - nostr_bip32_derive_child() -> Derive child key from parent
|
||||
* - nostr_bip32_derive_path() -> Derive keys from derivation path
|
||||
*
|
||||
* KEY DERIVATION:
|
||||
* - nostr_hkdf() -> HKDF key derivation (full)
|
||||
* - nostr_hkdf_extract() -> HKDF extract step only
|
||||
* - nostr_hkdf_expand() -> HKDF expand step only
|
||||
* - nostr_pbkdf2_hmac_sha512() -> PBKDF2 with HMAC-SHA512
|
||||
* - ecdh_shared_secret() -> ECDH shared secret computation
|
||||
*
|
||||
* UTILITIES & ENCODING:
|
||||
* - nostr_bytes_to_hex() -> Convert bytes to hex string
|
||||
* - nostr_hex_to_bytes() -> Convert hex string to bytes
|
||||
* - base64_encode() -> Base64 encoding
|
||||
* - base64_decode() -> Base64 decoding
|
||||
*
|
||||
* SYSTEM FUNCTIONS:
|
||||
* - nostr_crypto_init() -> Initialize crypto subsystem
|
||||
* - nostr_crypto_cleanup() -> Cleanup crypto subsystem
|
||||
*
|
||||
* ============================================================================
|
||||
* USAGE EXAMPLES:
|
||||
* ============================================================================
|
||||
*
|
||||
* Basic Event Creation:
|
||||
* cJSON* event = nostr_create_and_sign_event(1, "Hello Nostr!", NULL, private_key, time(NULL));
|
||||
* if (nostr_validate_event(event) == NOSTR_SUCCESS) { ... }
|
||||
*
|
||||
* Streaming SHA-256 (for large files):
|
||||
* nostr_sha256_ctx_t ctx;
|
||||
* nostr_sha256_init(&ctx);
|
||||
* // Process data in chunks...
|
||||
* nostr_sha256_update(&ctx, data, data_size);
|
||||
* nostr_sha256_final(&ctx, hash_output);
|
||||
*
|
||||
* File Hashing:
|
||||
* unsigned char file_hash[32];
|
||||
* nostr_sha256_file_stream("large_video.mp4", file_hash);
|
||||
*
|
||||
* Modern Encryption (NIP-44):
|
||||
* nostr_nip44_encrypt(sender_key, recipient_pubkey, "secret message", output, sizeof(output));
|
||||
*
|
||||
* HD Wallet Derivation:
|
||||
* nostr_bip32_key_from_seed(seed, 64, &master_key);
|
||||
* uint32_t path[] = {44, 1237, 0, 0, 0}; // m/44'/1237'/0'/0/0
|
||||
* nostr_bip32_derive_path(&master_key, path, 5, &derived_key);
|
||||
*
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -9,14 +9,28 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Include our secp256k1 wrapper for elliptic curve operations
|
||||
#include "crypto/nostr_secp256k1.h"
|
||||
// Forward declarations for crypto functions (private API)
|
||||
// These functions are implemented in crypto/ but not exposed through public headers
|
||||
|
||||
// Include our self-contained AES implementation for NIP-04
|
||||
#include "crypto/nostr_aes.h"
|
||||
// secp256k1 functions
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_pubkey;
|
||||
|
||||
// Include our ChaCha20 implementation for NIP-44
|
||||
#include "crypto/nostr_chacha20.h"
|
||||
typedef struct {
|
||||
unsigned char data[96];
|
||||
} nostr_secp256k1_keypair;
|
||||
|
||||
int nostr_secp256k1_context_create(void);
|
||||
void nostr_secp256k1_context_destroy(void);
|
||||
int nostr_secp256k1_ec_pubkey_parse(nostr_secp256k1_pubkey* pubkey, const unsigned char* input, size_t inputlen);
|
||||
int nostr_secp256k1_ecdh(unsigned char* output, const nostr_secp256k1_pubkey* pubkey, const unsigned char* privkey, void* hashfp, void* data);
|
||||
int nostr_secp256k1_ec_seckey_verify(const unsigned char* seckey);
|
||||
int nostr_secp256k1_ec_pubkey_create(nostr_secp256k1_pubkey* pubkey, const unsigned char* privkey);
|
||||
int nostr_secp256k1_ec_pubkey_serialize_compressed(unsigned char* output, const nostr_secp256k1_pubkey* pubkey);
|
||||
int nostr_secp256k1_keypair_create(nostr_secp256k1_keypair* keypair, const unsigned char* privkey);
|
||||
int nostr_secp256k1_schnorrsig_sign32(unsigned char* sig, const unsigned char* msg32, const nostr_secp256k1_keypair* keypair, const unsigned char* aux_rand32);
|
||||
int nostr_secp256k1_ec_seckey_tweak_add(unsigned char* seckey, const unsigned char* tweak);
|
||||
|
||||
|
||||
// =============================================================================
|
||||
@@ -328,6 +342,125 @@ int nostr_sha256(const unsigned char* data, size_t len, unsigned char* hash) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// STREAMING SHA-256 IMPLEMENTATION
|
||||
// =============================================================================
|
||||
|
||||
int nostr_sha256_init(nostr_sha256_ctx_t* ctx) {
|
||||
if (!ctx) return -1;
|
||||
|
||||
// Initialize SHA-256 state
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
|
||||
// Initialize counters and buffer
|
||||
ctx->bitlen = 0;
|
||||
ctx->buflen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nostr_sha256_update(nostr_sha256_ctx_t* ctx, const unsigned char* data, size_t len) {
|
||||
if (!ctx || !data) return -1;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ctx->buffer[ctx->buflen] = data[i];
|
||||
ctx->buflen++;
|
||||
|
||||
// Process complete blocks
|
||||
if (ctx->buflen == 64) {
|
||||
sha256_transform(ctx->state, ctx->buffer);
|
||||
ctx->bitlen += 512; // 64 bytes * 8 bits
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nostr_sha256_final(nostr_sha256_ctx_t* ctx, unsigned char* hash) {
|
||||
if (!ctx || !hash) return -1;
|
||||
|
||||
// Calculate final bit length
|
||||
uint64_t final_bitlen = ctx->bitlen + (ctx->buflen * 8);
|
||||
|
||||
// Pad the message
|
||||
ctx->buffer[ctx->buflen] = 0x80;
|
||||
ctx->buflen++;
|
||||
|
||||
// If not enough space for length, pad and process another block
|
||||
if (ctx->buflen > 56) {
|
||||
while (ctx->buflen < 64) {
|
||||
ctx->buffer[ctx->buflen] = 0x00;
|
||||
ctx->buflen++;
|
||||
}
|
||||
sha256_transform(ctx->state, ctx->buffer);
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
|
||||
// Pad with zeros up to 56 bytes
|
||||
while (ctx->buflen < 56) {
|
||||
ctx->buffer[ctx->buflen] = 0x00;
|
||||
ctx->buflen++;
|
||||
}
|
||||
|
||||
// Append length as big-endian 64-bit integer
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ctx->buffer[56 + i] = (final_bitlen >> (56 - i * 8)) & 0xff;
|
||||
}
|
||||
|
||||
// Process final block
|
||||
sha256_transform(ctx->state, ctx->buffer);
|
||||
|
||||
// Convert state to output bytes
|
||||
for (int i = 0; i < 8; i++) {
|
||||
hash[i * 4] = (ctx->state[i] >> 24) & 0xff;
|
||||
hash[i * 4 + 1] = (ctx->state[i] >> 16) & 0xff;
|
||||
hash[i * 4 + 2] = (ctx->state[i] >> 8) & 0xff;
|
||||
hash[i * 4 + 3] = ctx->state[i] & 0xff;
|
||||
}
|
||||
|
||||
// Clear sensitive data
|
||||
memory_clear(ctx, sizeof(nostr_sha256_ctx_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nostr_sha256_file_stream(const char* filename, unsigned char* hash) {
|
||||
if (!filename || !hash) return -1;
|
||||
|
||||
FILE* file = fopen(filename, "rb");
|
||||
if (!file) return -1;
|
||||
|
||||
nostr_sha256_ctx_t ctx;
|
||||
if (nostr_sha256_init(&ctx) != 0) {
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Process file in 4KB chunks for memory efficiency
|
||||
unsigned char buffer[4096];
|
||||
size_t bytes_read;
|
||||
|
||||
while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
|
||||
if (nostr_sha256_update(&ctx, buffer, bytes_read) != 0) {
|
||||
fclose(file);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
// Finalize and return result
|
||||
return nostr_sha256_final(&ctx, hash);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// HMAC IMPLEMENTATION
|
||||
// =============================================================================
|
||||
|
||||
@@ -45,6 +45,30 @@ void nostr_crypto_cleanup(void);
|
||||
// SHA-256 hash function
|
||||
int nostr_sha256(const unsigned char *data, size_t len, unsigned char *hash);
|
||||
|
||||
// =============================================================================
|
||||
// STREAMING SHA-256 FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// SHA-256 streaming context
|
||||
typedef struct {
|
||||
uint32_t state[8]; // Current hash state
|
||||
unsigned char buffer[64]; // Input buffer for incomplete blocks
|
||||
uint64_t bitlen; // Total bits processed
|
||||
size_t buflen; // Current buffer length
|
||||
} nostr_sha256_ctx_t;
|
||||
|
||||
// Initialize SHA-256 streaming context
|
||||
int nostr_sha256_init(nostr_sha256_ctx_t* ctx);
|
||||
|
||||
// Update SHA-256 context with new data
|
||||
int nostr_sha256_update(nostr_sha256_ctx_t* ctx, const unsigned char* data, size_t len);
|
||||
|
||||
// Finalize SHA-256 and output hash
|
||||
int nostr_sha256_final(nostr_sha256_ctx_t* ctx, unsigned char* hash);
|
||||
|
||||
// Stream SHA-256 hash of a file
|
||||
int nostr_sha256_file_stream(const char* filename, 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,
|
||||
|
||||
Reference in New Issue
Block a user