Add configurable timestamp randomization for NIP-59 gift wraps
This commit is contained in:
@@ -258,11 +258,12 @@ cJSON* nostr_nip17_create_relay_list_event(const char** relay_urls,
|
||||
* NIP-17: Send a direct message to recipients
|
||||
*/
|
||||
int nostr_nip17_send_dm(cJSON* dm_event,
|
||||
const char** recipient_pubkeys,
|
||||
int num_recipients,
|
||||
const unsigned char* sender_private_key,
|
||||
cJSON** gift_wraps_out,
|
||||
int max_gift_wraps) {
|
||||
const char** recipient_pubkeys,
|
||||
int num_recipients,
|
||||
const unsigned char* sender_private_key,
|
||||
cJSON** gift_wraps_out,
|
||||
int max_gift_wraps,
|
||||
long max_delay_sec) {
|
||||
if (!dm_event || !recipient_pubkeys || num_recipients <= 0 ||
|
||||
!sender_private_key || !gift_wraps_out || max_gift_wraps <= 0) {
|
||||
return -1;
|
||||
@@ -278,13 +279,13 @@ int nostr_nip17_send_dm(cJSON* dm_event,
|
||||
}
|
||||
|
||||
// Create seal for this recipient
|
||||
cJSON* seal = nostr_nip59_create_seal(dm_event, sender_private_key, recipient_public_key);
|
||||
cJSON* seal = nostr_nip59_create_seal(dm_event, sender_private_key, recipient_public_key, max_delay_sec);
|
||||
if (!seal) {
|
||||
continue; // Skip if sealing fails
|
||||
}
|
||||
|
||||
// Create gift wrap for this recipient
|
||||
cJSON* gift_wrap = nostr_nip59_create_gift_wrap(seal, recipient_pubkeys[i]);
|
||||
cJSON* gift_wrap = nostr_nip59_create_gift_wrap(seal, recipient_pubkeys[i], max_delay_sec);
|
||||
cJSON_Delete(seal); // Seal is now wrapped
|
||||
|
||||
if (!gift_wrap) {
|
||||
@@ -303,10 +304,10 @@ int nostr_nip17_send_dm(cJSON* dm_event,
|
||||
nostr_bytes_to_hex(sender_public_key, 32, sender_pubkey_hex);
|
||||
|
||||
// Create seal for sender
|
||||
cJSON* sender_seal = nostr_nip59_create_seal(dm_event, sender_private_key, sender_public_key);
|
||||
cJSON* sender_seal = nostr_nip59_create_seal(dm_event, sender_private_key, sender_public_key, max_delay_sec);
|
||||
if (sender_seal) {
|
||||
// Create gift wrap for sender
|
||||
cJSON* sender_gift_wrap = nostr_nip59_create_gift_wrap(sender_seal, sender_pubkey_hex);
|
||||
cJSON* sender_gift_wrap = nostr_nip59_create_gift_wrap(sender_seal, sender_pubkey_hex, max_delay_sec);
|
||||
cJSON_Delete(sender_seal);
|
||||
|
||||
if (sender_gift_wrap) {
|
||||
|
||||
@@ -97,6 +97,7 @@ cJSON* nostr_nip17_create_relay_list_event(const char** relay_urls,
|
||||
* @param sender_private_key 32-byte sender private key
|
||||
* @param gift_wraps_out Array to store resulting gift wrap events (caller must free)
|
||||
* @param max_gift_wraps Maximum number of gift wraps to create
|
||||
* @param max_delay_sec Maximum random timestamp delay in seconds (0 = no randomization)
|
||||
* @return Number of gift wrap events created, or -1 on error
|
||||
*/
|
||||
int nostr_nip17_send_dm(cJSON* dm_event,
|
||||
@@ -104,7 +105,8 @@ int nostr_nip17_send_dm(cJSON* dm_event,
|
||||
int num_recipients,
|
||||
const unsigned char* sender_private_key,
|
||||
cJSON** gift_wraps_out,
|
||||
int max_gift_wraps);
|
||||
int max_gift_wraps,
|
||||
long max_delay_sec);
|
||||
|
||||
/**
|
||||
* NIP-17: Receive and decrypt a direct message
|
||||
|
||||
@@ -26,12 +26,18 @@ static void memory_clear(const void *p, size_t len) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random timestamp within 2 days in the past (as per NIP-59 spec)
|
||||
* Create a random timestamp within max_delay_sec in the past (configurable)
|
||||
*/
|
||||
static time_t random_past_timestamp(void) {
|
||||
static time_t random_past_timestamp(long max_delay_sec) {
|
||||
time_t now = time(NULL);
|
||||
// Random time up to 2 days (172800 seconds) in the past
|
||||
long random_offset = (long)(rand() % 172800);
|
||||
|
||||
// If max_delay_sec is 0, return current timestamp (no randomization)
|
||||
if (max_delay_sec == 0) {
|
||||
return now;
|
||||
}
|
||||
|
||||
// Random time up to max_delay_sec in the past
|
||||
long random_offset = (long)(rand() % max_delay_sec);
|
||||
return now - random_offset;
|
||||
}
|
||||
|
||||
@@ -104,8 +110,8 @@ cJSON* nostr_nip59_create_rumor(int kind, const char* content, cJSON* tags,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Use provided timestamp or random past timestamp
|
||||
time_t event_time = (created_at == 0) ? random_past_timestamp() : created_at;
|
||||
// Use provided timestamp or random past timestamp (default to 0 for compatibility)
|
||||
time_t event_time = (created_at == 0) ? random_past_timestamp(0) : created_at;
|
||||
|
||||
// Create event structure (without id and sig - that's what makes it a rumor)
|
||||
cJSON* rumor = cJSON_CreateObject();
|
||||
@@ -142,7 +148,7 @@ cJSON* nostr_nip59_create_rumor(int kind, const char* content, cJSON* tags,
|
||||
* NIP-59: Create a seal (kind 13) wrapping a rumor
|
||||
*/
|
||||
cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private_key,
|
||||
const unsigned char* recipient_public_key) {
|
||||
const unsigned char* recipient_public_key, long max_delay_sec) {
|
||||
if (!rumor || !sender_private_key || !recipient_public_key) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -178,7 +184,7 @@ cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t seal_time = random_past_timestamp();
|
||||
time_t seal_time = random_past_timestamp(max_delay_sec);
|
||||
|
||||
cJSON_AddStringToObject(seal, "pubkey", sender_pubkey_hex);
|
||||
cJSON_AddNumberToObject(seal, "created_at", (double)seal_time);
|
||||
@@ -217,7 +223,7 @@ cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private
|
||||
/**
|
||||
* NIP-59: Create a gift wrap (kind 1059) wrapping a seal
|
||||
*/
|
||||
cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_key_hex) {
|
||||
cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_key_hex, long max_delay_sec) {
|
||||
if (!seal || !recipient_public_key_hex) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -272,7 +278,7 @@ cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_ke
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t wrap_time = random_past_timestamp();
|
||||
time_t wrap_time = random_past_timestamp(max_delay_sec);
|
||||
|
||||
cJSON_AddStringToObject(gift_wrap, "pubkey", random_pubkey_hex);
|
||||
cJSON_AddNumberToObject(gift_wrap, "created_at", (double)wrap_time);
|
||||
|
||||
@@ -33,19 +33,21 @@ cJSON* nostr_nip59_create_rumor(int kind, const char* content, cJSON* tags,
|
||||
* @param rumor The rumor event to seal (cJSON object)
|
||||
* @param sender_private_key 32-byte sender private key
|
||||
* @param recipient_public_key 32-byte recipient public key (x-only)
|
||||
* @param max_delay_sec Maximum random timestamp delay in seconds (0 = no randomization)
|
||||
* @return cJSON object representing the seal event, or NULL on error
|
||||
*/
|
||||
cJSON* nostr_nip59_create_seal(cJSON* rumor, const unsigned char* sender_private_key,
|
||||
const unsigned char* recipient_public_key);
|
||||
const unsigned char* recipient_public_key, long max_delay_sec);
|
||||
|
||||
/**
|
||||
* NIP-59: Create a gift wrap (kind 1059) wrapping a seal
|
||||
*
|
||||
* @param seal The seal event to wrap (cJSON object)
|
||||
* @param recipient_public_key_hex Recipient's public key in hex format
|
||||
* @param max_delay_sec Maximum random timestamp delay in seconds (0 = no randomization)
|
||||
* @return cJSON object representing the gift wrap event, or NULL on error
|
||||
*/
|
||||
cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_key_hex);
|
||||
cJSON* nostr_nip59_create_gift_wrap(cJSON* seal, const char* recipient_public_key_hex, long max_delay_sec);
|
||||
|
||||
/**
|
||||
* NIP-59: Unwrap a gift wrap to get the seal
|
||||
|
||||
Reference in New Issue
Block a user