nostr_core_lib/nostr_core/nip006.c

119 lines
3.7 KiB
C

/*
* NOSTR Core Library - NIP-006: Key Derivation from Mnemonic
*/
#include "nip006.h"
#include "utils.h"
#include "nostr_crypto.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key) {
if (!private_key || !public_key) {
return NOSTR_ERROR_INVALID_INPUT;
}
// Generate random entropy using /dev/urandom
FILE* urandom = fopen("/dev/urandom", "rb");
if (!urandom) {
return NOSTR_ERROR_IO_FAILED;
}
if (fread(private_key, 1, 32, urandom) != 32) {
fclose(urandom);
return NOSTR_ERROR_IO_FAILED;
}
fclose(urandom);
// Validate private key
if (nostr_ec_private_key_verify(private_key) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
// Generate public key from private key (already x-only for NOSTR)
if (nostr_ec_public_key_from_private_key(private_key, public_key) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
return NOSTR_SUCCESS;
}
int nostr_generate_mnemonic_and_keys(char* mnemonic, size_t mnemonic_size,
int account, unsigned char* private_key,
unsigned char* public_key) {
if (!mnemonic || mnemonic_size < 256 || !private_key || !public_key) {
return NOSTR_ERROR_INVALID_INPUT;
}
// Generate entropy for 12-word mnemonic
unsigned char entropy[16];
FILE* urandom = fopen("/dev/urandom", "rb");
if (!urandom) {
return NOSTR_ERROR_IO_FAILED;
}
if (fread(entropy, 1, sizeof(entropy), urandom) != sizeof(entropy)) {
fclose(urandom);
return NOSTR_ERROR_IO_FAILED;
}
fclose(urandom);
// Generate mnemonic from entropy
if (nostr_bip39_mnemonic_from_bytes(entropy, sizeof(entropy), mnemonic) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
// Derive keys from the generated mnemonic
return nostr_derive_keys_from_mnemonic(mnemonic, account, private_key, public_key);
}
int nostr_derive_keys_from_mnemonic(const char* mnemonic, int account,
unsigned char* private_key, unsigned char* public_key) {
if (!mnemonic || !private_key || !public_key) {
return NOSTR_ERROR_INVALID_INPUT;
}
// Validate mnemonic
if (nostr_bip39_mnemonic_validate(mnemonic) != 0) {
return NOSTR_ERROR_INVALID_INPUT;
}
// Convert mnemonic to seed
unsigned char seed[64];
if (nostr_bip39_mnemonic_to_seed(mnemonic, "", seed, sizeof(seed)) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
// Derive master key from seed
nostr_hd_key_t master_key;
if (nostr_bip32_key_from_seed(seed, sizeof(seed), &master_key) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
// NIP-06 path: m/44'/1237'/account'/0/0
nostr_hd_key_t derived_key;
uint32_t path[] = {
0x80000000 + 44, // 44' (hardened)
0x80000000 + 1237, // 1237' (hardened)
0x80000000 + account, // account' (hardened)
0, // 0 (not hardened)
0 // 0 (not hardened)
};
if (nostr_bip32_derive_path(&master_key, path, sizeof(path) / sizeof(path[0]), &derived_key) != 0) {
return NOSTR_ERROR_CRYPTO_FAILED;
}
// Extract private key and public key
memcpy(private_key, derived_key.private_key, 32);
memcpy(public_key, derived_key.public_key + 1, 32); // Remove compression prefix for x-only
return NOSTR_SUCCESS;
}
// Note: nostr_detect_input_type, nostr_decode_nsec, and nostr_decode_npub
// are implemented in NIP-019 to avoid multiple definitions