17#ifndef WIN32_LEAN_AND_MEAN
18#define WIN32_LEAN_AND_MEAN
22#elif defined(__linux__)
24#include <sys/random.h>
26#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
43 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0x5d, 0x57, 0x6e, 0x73, 0x57, 0xa4, 0x50, 0x1d,
46 0xdf, 0xe9, 0x2f, 0x46, 0x68, 0x1b, 0x20, 0xa0,
47 0xb2, 0x92, 0x66, 0xf8, 0xfd, 0xd3, 0x36, 0x23,
48 0x17, 0x0b, 0xa9, 0x62, 0x08, 0xc6, 0x3e, 0x47,
49 0x58, 0xfb, 0xa2, 0xd2, 0xca, 0xf0, 0xc1, 0x8d,
50 0xc4, 0x8a, 0xf1, 0x1c, 0xeb, 0xe3, 0xf4, 0x64,
62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd,
64 0x75, 0x5d, 0xb9, 0xcd, 0x5e, 0x91, 0x40, 0x77,
65 0x7f, 0xa4, 0xbd, 0x19, 0xa0, 0x6c, 0x82, 0x83,
66 0x9d, 0x67, 0x1c, 0xd5, 0x81, 0xc6, 0x9b, 0xc5,
67 0xe6, 0x97, 0xf5, 0xe4, 0x5b, 0xcd, 0x07, 0xc5,
68 0x2e, 0xc3, 0x73, 0xa8, 0xbd, 0xc5, 0x98, 0xb4,
69 0x49, 0x3f, 0x50, 0xa1, 0x38, 0x0e, 0x12, 0x81,
81 "bit_index_out_of_range",
88 "uninitialized_state",
96 "entropy_unavailable",
97 "backend_rejected_input",
98 "hash_to_curve_exhausted",
100 "generator_order_check_failed",
102 "transcript_check_failed",
107 "hex input contains a non-hexadecimal character",
108 "hex input has an invalid length",
109 "input does not have the required fixed size",
110 "operation overflowed the target representation",
111 "operation underflowed the target representation",
112 "narrowing conversion would discard non-zero bits",
113 "division by zero is not permitted",
114 "bit index is outside the valid range",
115 "input is outside the documented valid range",
116 "input must not be empty",
117 "related inputs do not have matching sizes",
118 "required value is missing",
119 "symbol encoding is malformed",
120 "symbol is well-formed but not supported",
121 "object must be initialized before this operation",
122 "index is outside the valid range",
123 "inputs imply an invalid shape or dimension",
124 "value violates a required boolean constraint",
125 "value violates a required equality constraint",
126 "prepared state is bound to a different secret, message, or topic",
127 "unable to open the requested file or stream",
128 "unable to write the requested file or stream",
129 "unable to obtain secure operating-system randomness",
130 "the cryptographic backend rejected the supplied input",
131 "hash-to-curve sampling exhausted all retry attempts",
132 "backend returned an unexpected serialized size",
133 "fixed generator failed its subgroup order check",
134 "internal consistency check failed",
135 "internally generated transcript failed validation",
139 volatile unsigned char* out = (
volatile unsigned char*)data;
149 for (i = 0; i < size; ++i) {
150 if (lhs[i] < rhs[i]) {
153 if (lhs[i] > rhs[i]) {
162 const unsigned char* upper_bound) {
174 const unsigned char* ikm,
176 const unsigned char* salt,
178 const unsigned char* info,
180 static const unsigned char kZeroSalt[32] = {0};
181 unsigned char prk[32];
184 size_t block_index = 0;
186 if (out_len != 0 && out == NULL) {
189 if (ikm_len != 0 && ikm == NULL) {
192 if (salt_len != 0 && salt == NULL) {
195 if (info_len != 0 && info == NULL) {
199 memset(prk, 0,
sizeof(prk));
200 memset(t, 0,
sizeof(t));
202 salt_len == 0 ? kZeroSalt : salt,
203 salt_len == 0 ?
sizeof(kZeroSalt) : salt_len,
207 while (offset < out_len) {
208 const size_t prev_len = block_index == 0 ? 0 :
sizeof(t);
209 const size_t input_len = prev_len + info_len + 1;
210 unsigned char* input = (
unsigned char*)malloc(input_len == 0 ? 1 : input_len);
218 memcpy(input, t, prev_len);
221 memcpy(input + prev_len, info, info_len);
223 input[input_len - 1] = (
unsigned char)(block_index + 1);
228 copy_len =
sizeof(t);
229 if (copy_len > out_len - offset) {
230 copy_len = out_len - offset;
232 memcpy(out + offset, t, copy_len);
244 const unsigned int index = (
unsigned int)code;
245 if (index >= count) {
253 const unsigned int index = (
unsigned int)code;
254 if (index >= count) {
255 return "unknown status code";
261 if (bytes_len != 0 && bytes == NULL) {
265 while (bytes_len != 0) {
266 ULONG chunk = (ULONG)(bytes_len > 0xFFFFFFFFu ? 0xFFFFFFFFu : bytes_len);
267 NTSTATUS status = BCryptGenRandom(NULL, bytes, chunk, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
275#elif defined(__linux__)
276 while (bytes_len != 0) {
277 ssize_t written = getrandom(bytes, bytes_len, 0);
279 bytes += (size_t)written;
280 bytes_len -= (size_t)written;
283 if (written < 0 && errno == EINTR) {
289#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
290 arc4random_buf(bytes, bytes_len);
293 FILE* file = fopen(
"/dev/urandom",
"rb");
298 read_count = fread(bytes, 1, bytes_len, file);
300 if (read_count != bytes_len) {
317 if (out_secret_key == NULL) {
327 out_secret_key[0] &= 0x3f;
335 const unsigned char* seed,
337 static const unsigned char kInfo[] =
"Purify/KeyGen";
338 unsigned char salt[1];
339 unsigned int attempt;
342 if (out_secret_key == NULL) {
346 if (seed_len != 0 && seed == NULL) {
354 for (attempt = 0; attempt < 256; ++attempt) {
355 salt[0] = (
unsigned char)attempt;
368 out_secret_key[0] &= 0x3f;
static int purify_core_compare_be(const unsigned char *lhs, const unsigned char *rhs, size_t size)
static void purify_core_secure_clear(void *data, size_t size)
purify_error_code purify_core_sample_secret_key(unsigned char out_secret_key[PURIFY_SECRET_KEY_BYTES])
purify_error_code purify_fill_secure_random(unsigned char *bytes, size_t bytes_len)
Fills a caller-owned buffer with secure operating-system randomness.
const char * purify_error_message(purify_error_code code)
Returns a human-facing description for one status code.
static purify_error_code purify_core_validate_below(const unsigned char *value, size_t size, const unsigned char *upper_bound)
static const char *const kErrorNames[]
static const char *const kErrorMessages[]
const char * purify_error_name(purify_error_code code)
Returns a stable programmatic name for one status code.
purify_error_code purify_validate_secret_key(const unsigned char secret_key[PURIFY_SECRET_KEY_BYTES])
Validates one packed Purify secret key.
static const unsigned char kPackedSecretKeySpaceSize[PURIFY_SECRET_KEY_BYTES]
purify_error_code purify_core_seed_secret_key(unsigned char out_secret_key[PURIFY_SECRET_KEY_BYTES], const unsigned char *seed, size_t seed_len)
static purify_error_code purify_core_hkdf_sha256(unsigned char *out, size_t out_len, const unsigned char *ikm, size_t ikm_len, const unsigned char *salt, size_t salt_len, const unsigned char *info, size_t info_len)
static const unsigned char kPackedPublicKeySpaceSize[PURIFY_PUBLIC_KEY_BYTES]
purify_error_code purify_validate_public_key(const unsigned char public_key[PURIFY_PUBLIC_KEY_BYTES])
Validates one packed Purify public key.
#define PURIFY_SECRET_KEY_BYTES
#define PURIFY_PUBLIC_KEY_BYTES
purify_error_code
Machine-readable status code returned by the Purify C core.
@ PURIFY_ERROR_MISSING_VALUE
@ PURIFY_ERROR_ENTROPY_UNAVAILABLE
@ PURIFY_ERROR_INTERNAL_MISMATCH
@ PURIFY_ERROR_RANGE_VIOLATION
Narrow C ABI exposing secp256k1 scalar and HMAC helpers to the C++ headers.
void purify_hmac_sha256(unsigned char output32[32], const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len)
Computes HMAC-SHA256 over a byte string.