This commit is contained in:
2025-11-29 16:43:03 -06:00
parent efe93b7206
commit 9f696a0342
7 changed files with 400 additions and 220 deletions

View File

@@ -238,6 +238,7 @@ src += ['quickjs.c', 'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c']
scripts = [
'nota.c',
'js.c',
'mersenne.c',
'qop.c',
'wildstar.c',
'fit.c',

View File

@@ -5,176 +5,284 @@
#include "monocypher.h"
static inline void to_hex(const uint8_t *in, size_t in_len, char *out)
{
static const char hexchars[] = "0123456789abcdef";
for (size_t i = 0; i < in_len; i++) {
out[2*i ] = hexchars[(in[i] >> 4) & 0x0F];
out[2*i + 1] = hexchars[ in[i] & 0x0F];
// External declaration if not in cell.h
void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v);
/*
Crypto Module Documentation
This module provides cryptographic functions using the Monocypher library.
All inputs and outputs are Blobs.
Functions:
- keypair() -> { public: Blob(256 bits), private: Blob(256 bits) }
Generates a new random X25519 keypair.
- shared(public_key, private_key) -> Blob(256 bits)
Computes a shared secret from your private key and another's public key (X25519).
Input keys must be 256 bits (32 bytes).
- blake2(data, [hash_size_bytes=32]) -> Blob
Computes the BLAKE2b hash of the data.
Default hash size is 32 bytes (256 bits). Supports 1-64 bytes.
- sign(secret_key, message) -> Blob(512 bits)
Signs a message using EdDSA.
secret_key must be 512 bits (64 bytes).
(Note: If you have a 32-byte seed, extend it first or use appropriate key generation).
Returns a 64-byte signature.
- verify(signature, public_key, message) -> bool
Verifies an EdDSA signature.
signature: 512 bits (64 bytes).
public_key: 256 bits (32 bytes).
Returns true if valid, false otherwise.
- lock(key, nonce, message, [ad]) -> Blob
Encrypts and authenticates a message using XChaCha20-Poly1305.
key: 256 bits (32 bytes).
nonce: 192 bits (24 bytes).
ad: Optional associated data (Blob).
Returns a blob containing the ciphertext followed by the 16-byte MAC.
- unlock(key, nonce, ciphertext_with_mac, [ad]) -> Blob or null
Decrypts and verifies a message.
key: 256 bits (32 bytes).
nonce: 192 bits (24 bytes).
ciphertext_with_mac: Must include the 16-byte MAC at the end.
ad: Optional associated data (Blob).
Returns the plaintext Blob if successful, or null if verification fails.
*/
// Helper to get blob data and check exact bit length
static void *get_blob_check_bits(JSContext *js, JSValue val, size_t expected_bits, const char *name) {
size_t bits;
void *data = js_get_blob_data_bits(js, &bits, val);
if (!data) {
JS_ThrowTypeError(js, "%s: expected a blob", name);
return NULL;
}
out[2 * in_len] = '\0'; // null-terminate
if (bits != expected_bits) {
JS_ThrowTypeError(js, "%s: expected %zu bits, got %zu", name, expected_bits, bits);
return NULL;
}
return data;
}
static inline int nibble_from_char(char c, uint8_t *nibble)
{
if (c >= '0' && c <= '9') { *nibble = (uint8_t)(c - '0'); return 0; }
if (c >= 'a' && c <= 'f') { *nibble = (uint8_t)(c - 'a' + 10); return 0; }
if (c >= 'A' && c <= 'F') { *nibble = (uint8_t)(c - 'A' + 10); return 0; }
return -1; // invalid char
}
static inline int from_hex(const char *hex, uint8_t *out, size_t out_len)
{
for (size_t i = 0; i < out_len; i++) {
uint8_t hi, lo;
if (nibble_from_char(hex[2*i], &hi) < 0) return -1;
if (nibble_from_char(hex[2*i + 1], &lo) < 0) return -1;
out[i] = (uint8_t)((hi << 4) | lo);
// Helper to get any blob data (checking it is a stoned blob)
static void *get_blob_any(JSContext *js, JSValue val, size_t *out_bits, const char *name) {
void *data = js_get_blob_data_bits(js, out_bits, val);
if (!data) {
JS_ThrowTypeError(js, "%s: expected a blob", name);
return NULL;
}
return 0;
}
// Convert a JSValue containing a 64-character hex string into a 32-byte array.
static inline void js2crypto(JSContext *js, JSValue v, uint8_t *crypto)
{
size_t hex_len;
const char *hex_str = JS_ToCStringLen(js, &hex_len, v);
if (!hex_str)
return;
if (hex_len != 64) {
JS_FreeCString(js, hex_str);
JS_ThrowTypeError(js, "js2crypto: expected 64-hex-char string");
return;
}
if (from_hex(hex_str, crypto, 32) < 0) {
JS_FreeCString(js, hex_str);
JS_ThrowTypeError(js, "js2crypto: invalid hex encoding");
return;
}
JS_FreeCString(js, hex_str);
}
static inline JSValue crypto2js(JSContext *js, const uint8_t *crypto)
{
char hex[65]; // 32*2 + 1 for null terminator
to_hex(crypto, 32, hex);
return JS_NewString(js, hex);
return data;
}
JSValue js_crypto_keypair(JSContext *js, JSValue self, int argc, JSValue *argv) {
JSValue ret = JS_NewObject(js);
JSValue ret = JS_NewObject(js);
uint8_t public[32];
uint8_t private[32];
JSValue global = JS_GetGlobalObject(js);
JSValue os = JS_GetPropertyStr(js, global, "os");
JSValue random_blob = JS_GetPropertyStr(js, os, "random_blob");
JSValue size_val = JS_NewInt32(js, 32);
JSValue blob = JS_Call(js, random_blob, os, 1, &size_val);
size_t len;
uint8_t *data = js_get_blob_data(js, &len, blob);
if (!data || len != 32) {
JS_FreeValue(js, blob);
// Generate 32 random bytes using os.random_blob
JSValue global = JS_GetGlobalObject(js);
JSValue os = JS_GetPropertyStr(js, global, "os");
JSValue random_blob = JS_GetPropertyStr(js, os, "random_blob");
JSValue size_val = JS_NewInt32(js, 32); // 32 bytes
JSValue blob = JS_Call(js, random_blob, os, 1, &size_val);
JS_FreeValue(js, size_val);
JS_FreeValue(js, random_blob);
JS_FreeValue(js, os);
JS_FreeValue(js, global);
return JS_ThrowInternalError(js, "failed to get random bytes");
}
memcpy(private, data, 32);
JS_FreeValue(js, blob);
JS_FreeValue(js, size_val);
JS_FreeValue(js, random_blob);
JS_FreeValue(js, os);
JS_FreeValue(js, global);
if (JS_IsException(blob)) return blob;
private[0] &= 248;
private[31] &= 127;
private[31] |= 64;
size_t bits;
uint8_t *data = js_get_blob_data_bits(js, &bits, blob);
if (!data || bits != 256) {
JS_FreeValue(js, blob);
return JS_ThrowInternalError(js, "failed to get 256 bits of random bytes");
}
crypto_x25519_public_key(public,private);
uint8_t priv[32];
uint8_t pub[32];
JS_SetPropertyStr(js, ret, "public", crypto2js(js, public));
JS_SetPropertyStr(js, ret, "private", crypto2js(js,private));
return ret;
memcpy(priv, data, 32);
JS_FreeValue(js, blob); // Done with random blob
// Clamp the private key
priv[0] &= 248;
priv[31] &= 127;
priv[31] |= 64;
crypto_x25519_public_key(pub, priv);
JS_SetPropertyStr(js, ret, "public", js_new_blob_stoned_copy(js, pub, 32));
JS_SetPropertyStr(js, ret, "private", js_new_blob_stoned_copy(js, priv, 32));
return ret;
}
JSValue js_crypto_shared(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 1 || !JS_IsObject(argv[0])) {
return JS_ThrowTypeError(js, "crypto.shared: expected an object argument");
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.shared: expected public_key, private_key");
}
JSValue obj = argv[0];
uint8_t *pub = get_blob_check_bits(js, argv[0], 256, "crypto.shared public_key");
if (!pub) return JS_EXCEPTION;
JSValue val_pub = JS_GetPropertyStr(js, obj, "public");
if (JS_IsException(val_pub)) {
JS_FreeValue(js, val_pub);
return JS_EXCEPTION;
}
JSValue val_priv = JS_GetPropertyStr(js, obj, "private");
if (JS_IsException(val_priv)) {
JS_FreeValue(js, val_pub);
JS_FreeValue(js, val_priv);
return JS_EXCEPTION;
}
uint8_t pub[32], priv[32];
js2crypto(js, val_pub, pub);
js2crypto(js, val_priv, priv);
JS_FreeValue(js, val_pub);
JS_FreeValue(js, val_priv);
uint8_t *priv = get_blob_check_bits(js, argv[1], 256, "crypto.shared private_key");
if (!priv) return JS_EXCEPTION;
uint8_t shared[32];
crypto_x25519(shared, priv, pub);
return crypto2js(js, shared);
return js_new_blob_stoned_copy(js, shared, 32);
}
JSValue js_crypto_hash(JSContext *js, JSValue self, int argc, JSValue *argv)
JSValue js_crypto_blake2(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js, "hash requires at least one argument");
return JS_ThrowTypeError(js, "crypto.blake2: expected data blob");
// Get input data
size_t data_len;
void *data = js_get_blob_data(js, &data_len, argv[0]);
if (!data)
return JS_ThrowTypeError(js, "hash: first argument must be an ArrayBuffer");
size_t data_bits;
uint8_t *data = get_blob_any(js, argv[0], &data_bits, "crypto.blake2 data");
if (!data) return JS_EXCEPTION;
// Get hash length (default 32)
int32_t hash_len = 32;
if (argc > 1) {
if (JS_ToInt32(js, &hash_len, argv[1]))
return JS_EXCEPTION;
if (hash_len < 1 || hash_len > 64)
return JS_ThrowRangeError(js, "hash length must be between 1 and 64");
return JS_ThrowRangeError(js, "crypto.blake2: hash length must be between 1 and 64 bytes");
}
// Allocate output buffer
uint8_t *hash = js_malloc(js, hash_len);
if (!hash)
return JS_EXCEPTION;
uint8_t hash[64];
// Use (bits + 7) / 8 to get byte length covering all bits
crypto_blake2b(hash, hash_len, data, (data_bits + 7) / 8);
// Compute BLAKE2b hash
crypto_blake2b(hash, hash_len, data, data_len);
return js_new_blob_stoned_copy(js, hash, hash_len);
}
JSValue js_crypto_sign(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 2) return JS_ThrowTypeError(js, "crypto.sign: expected secret_key, message");
// Return as blob
JSValue result = js_new_blob_stoned_copy(js, hash, hash_len);
js_free(js, hash);
return result;
uint8_t *sk = get_blob_check_bits(js, argv[0], 512, "crypto.sign secret_key");
if (!sk) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[1], &msg_bits, "crypto.sign message");
if (!msg) return JS_EXCEPTION;
uint8_t sig[64];
crypto_eddsa_sign(sig, sk, msg, (msg_bits + 7) / 8);
return js_new_blob_stoned_copy(js, sig, 64);
}
JSValue js_crypto_verify(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.verify: expected signature, public_key, message");
uint8_t *sig = get_blob_check_bits(js, argv[0], 512, "crypto.verify signature");
if (!sig) return JS_EXCEPTION;
uint8_t *pk = get_blob_check_bits(js, argv[1], 256, "crypto.verify public_key");
if (!pk) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[2], &msg_bits, "crypto.verify message");
if (!msg) return JS_EXCEPTION;
int ret = crypto_eddsa_check(sig, pk, msg, (msg_bits + 7) / 8);
return JS_NewBool(js, ret == 0);
}
JSValue js_crypto_lock(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.lock: expected key, nonce, message, [ad]");
uint8_t *key = get_blob_check_bits(js, argv[0], 256, "crypto.lock key");
if (!key) return JS_EXCEPTION;
uint8_t *nonce = get_blob_check_bits(js, argv[1], 192, "crypto.lock nonce");
if (!nonce) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[2], &msg_bits, "crypto.lock message");
if (!msg) return JS_EXCEPTION;
size_t msg_len = (msg_bits + 7) / 8;
size_t ad_len = 0;
uint8_t *ad = NULL;
if (argc > 3 && !JS_IsNull(argv[3])) {
size_t ad_bits;
ad = get_blob_any(js, argv[3], &ad_bits, "crypto.lock ad");
if (!ad) return JS_EXCEPTION;
ad_len = (ad_bits + 7) / 8;
}
size_t out_len = msg_len + 16;
uint8_t *out = malloc(out_len);
if (!out) return JS_ThrowOutOfMemory(js);
// Output: [Ciphertext (msg_len)] [MAC (16)]
crypto_aead_lock(out, out + msg_len, key, nonce, ad, ad_len, msg, msg_len);
JSValue ret = js_new_blob_stoned_copy(js, out, out_len);
free(out);
return ret;
}
JSValue js_crypto_unlock(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.unlock: expected key, nonce, ciphertext, [ad]");
uint8_t *key = get_blob_check_bits(js, argv[0], 256, "crypto.unlock key");
if (!key) return JS_EXCEPTION;
uint8_t *nonce = get_blob_check_bits(js, argv[1], 192, "crypto.unlock nonce");
if (!nonce) return JS_EXCEPTION;
size_t cipher_bits;
uint8_t *cipher = get_blob_any(js, argv[2], &cipher_bits, "crypto.unlock ciphertext");
if (!cipher) return JS_EXCEPTION;
size_t cipher_len = (cipher_bits + 7) / 8;
if (cipher_len < 16) return JS_ThrowTypeError(js, "crypto.unlock: ciphertext too short (min 16 bytes)");
size_t msg_len = cipher_len - 16;
size_t ad_len = 0;
uint8_t *ad = NULL;
if (argc > 3 && !JS_IsNull(argv[3])) {
size_t ad_bits;
ad = get_blob_any(js, argv[3], &ad_bits, "crypto.unlock ad");
if (!ad) return JS_EXCEPTION;
ad_len = (ad_bits + 7) / 8;
}
uint8_t *out = malloc(msg_len > 0 ? msg_len : 1);
if (!out) return JS_ThrowOutOfMemory(js);
// MAC is at cipher + msg_len
const uint8_t *mac = cipher + msg_len;
if (crypto_aead_unlock(out, mac, key, nonce, ad, ad_len, cipher, msg_len) != 0) {
free(out);
return JS_NULL;
}
JSValue ret = js_new_blob_stoned_copy(js, out, msg_len);
free(out);
return ret;
}
static const JSCFunctionListEntry js_crypto_funcs[] = {
JS_CFUNC_DEF("keypair", 0, js_crypto_keypair),
JS_CFUNC_DEF("shared", 1, js_crypto_shared),
JS_CFUNC_DEF("hash", 2, js_crypto_hash),
JS_CFUNC_DEF("shared", 2, js_crypto_shared),
JS_CFUNC_DEF("blake2", 1, js_crypto_blake2),
JS_CFUNC_DEF("sign", 2, js_crypto_sign),
JS_CFUNC_DEF("verify", 3, js_crypto_verify),
JS_CFUNC_DEF("lock", 3, js_crypto_lock),
JS_CFUNC_DEF("unlock", 3, js_crypto_unlock),
};
JSValue js_crypto_use(JSContext *js)

148
scripts/mersenne.c Normal file
View File

@@ -0,0 +1,148 @@
#include "quickjs.h"
#include "cell.h"
#include <stdint.h>
#include "qjs_macros.h"
// Random number generation constants for MT19937-64
#define STATE_VECTOR_LENGTH 312
#define STATE_VECTOR_M 156
#define NN STATE_VECTOR_LENGTH
#define MM STATE_VECTOR_M
#define MATRIX_A 0xB5026F5AA96619E9ULL
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
typedef struct tagMTRand {
uint64_t mt[STATE_VECTOR_LENGTH];
int32_t index;
} MTRand;
// Random number generation functions
static void m_seedRand(MTRand* rand, uint64_t seed) {
rand->mt[0] = seed;
for(rand->index = 1; rand->index < NN; rand->index++) {
rand->mt[rand->index] = (6364136223846793005ULL * (rand->mt[rand->index-1] ^ (rand->mt[rand->index-1] >> 62)) + rand->index);
}
}
static int64_t genRandLong(MTRand* rand) {
int i;
uint64_t x;
static uint64_t mag01[2] = {0ULL, MATRIX_A};
if (rand->index >= NN) { /* generate NN words at one time */
/* if init_genrand64() has not been called, */
/* a default initial seed is used */
if (rand->index == NN+1)
m_seedRand(rand, 5489ULL);
for (i = 0; i < NN-MM; i++) {
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
rand->mt[i] = rand->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
for (; i < NN-1; i++) {
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
rand->mt[i] = rand->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
x = (rand->mt[NN-1] & UM) | (rand->mt[0] & LM);
rand->mt[NN-1] = rand->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
rand->index = 0;
}
x = rand->mt[rand->index++];
x ^= (x >> 29) & 0x5555555555555555ULL;
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
x ^= (x >> 43);
return (int64_t)(x & 0x000FFFFFFFFFFFFFULL); /* return 52-bit value safe for JS */
}
static double genRand(MTRand* rand) {
/* generates a random number on [0,1)-real-interval */
return (genRandLong(rand) >> 11) * (1.0/9007199254740992.0);
}
/* JS Class Definition */
static JSClassID js_mersenne_class_id;
static void js_mersenne_finalizer(JSRuntime *rt, JSValue val) {
MTRand *mrand = JS_GetOpaque(val, js_mersenne_class_id);
js_free_rt(rt, mrand);
}
static JSClassDef js_mersenne_class = {
"Mersenne",
.finalizer = js_mersenne_finalizer,
};
static MTRand *js2mersenne(JSContext *js, JSValue v) {
return JS_GetOpaque(v, js_mersenne_class_id);
}
/* Methods */
JSC_CCALL(mersenne_get,
MTRand *mrand = js2mersenne(js, self);
if (!mrand) return JS_ThrowTypeError(js, "Invalid mersenne context");
return JS_NewFloat64(js, genRand(mrand));
)
static const JSCFunctionListEntry js_mersenne_funcs[] = {
JS_CFUNC_DEF("get", 0, js_mersenne_get),
};
/* Factory Function */
static JSValue js_mersenne_use_call(JSContext *js, JSValueConst func_obj,
JSValueConst this_val, int argc, JSValueConst *argv)
{
uint64_t seed;
if (argc == 0 || JS_IsNull(argv[0])) {
// Use OS random
extern int randombytes(void *buf, size_t n);
randombytes(&seed, 8);
} else {
if (JS_ToFloat64(js, (double*)&seed, argv[0])) {
// Fallback to number if bigint fails or is not provided as bigint
double d;
if (JS_ToFloat64(js, &d, argv[0])) return JS_EXCEPTION;
seed = (uint64_t)d;
}
}
MTRand *mrand = js_malloc(js, sizeof(MTRand));
if (!mrand) return JS_ThrowOutOfMemory(js);
m_seedRand(mrand, seed);
JSValue obj = JS_NewObjectClass(js, js_mersenne_class_id);
if (JS_IsException(obj)) {
js_free(js, mrand);
return obj;
}
JS_SetOpaque(obj, mrand);
// Store seed as a read-only property
JS_DefinePropertyValueStr(js, obj, "seed",
JS_NewFloat64(js, seed),
JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE // Read-only (no WRITABLE)
);
return obj;
}
JSValue js_mersenne_use(JSContext *js)
{
JS_NewClassID(&js_mersenne_class_id);
JS_NewClass(JS_GetRuntime(js), js_mersenne_class_id, &js_mersenne_class);
JSValue proto = JS_NewObject(js);
JS_SetPropertyFunctionList(js, proto, js_mersenne_funcs, sizeof(js_mersenne_funcs)/sizeof(JSCFunctionListEntry));
JS_SetClassProto(js, js_mersenne_class_id, proto);
// Return the factory function
return JS_NewCFunction2(js, js_mersenne_use_call, "mersenne", 1, JS_CFUNC_generic, 0);
}

View File

@@ -476,11 +476,13 @@ int randombytes(void *buf, size_t n) {
#else
// ------- Other Unix: read from /dev/urandom -------
static int rand_fd = -1;
int randombytes(void *buf, size_t n) {
int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) return -1;
ssize_t r = read(fd, buf, n);
close(fd);
if (rand_fd < 0) {
rand_fd = open("/dev/urandom", O_RDONLY);
if (rand_fd < 0) return -1;
}
ssize_t r = read(rand_fd, buf, n);
return (r == (ssize_t)n) ? 0 : -1;
}
#endif

View File

@@ -34,8 +34,6 @@ typedef struct letter {
};
} letter;
#define STATE_VECTOR_LENGTH 312
#define STATE_VECTOR_M 156
#define ACTOR_IDLE 0 // Actor not doing anything
#define ACTOR_READY 1 // Actor ready for a turn
@@ -46,11 +44,6 @@ typedef struct letter {
extern int tracy_profiling_enabled;
typedef struct tagMTRand {
uint64_t mt[STATE_VECTOR_LENGTH];
int32_t index;
} MTRand;
typedef struct cell_rt {
JSContext *context;
#ifdef HAVE_MIMALLOC
@@ -67,7 +60,6 @@ mi_heap_t *heap;
SDL_Mutex *msg_mutex; /* For message queue and timers queue */
char *id;
MTRand mrand;
int idx_count;
@@ -116,6 +108,8 @@ JSValue bool2js(JSContext *js, int b);
double js2number(JSContext *js, JSValue v);
JSValue number2js(JSContext *js, double g);
double cell_random();
#ifdef __cplusplus
}
#endif

View File

@@ -20,67 +20,6 @@
#include <dlfcn.h>
#endif
// Random number generation constants for MT19937-64
#define NN STATE_VECTOR_LENGTH
#define MM STATE_VECTOR_M
#define MATRIX_A 0xB5026F5AA96619E9ULL
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
// Random number generation functions
void m_seedRand(MTRand* rand, uint64_t seed) {
rand->mt[0] = seed;
for(rand->index = 1; rand->index < NN; rand->index++) {
rand->mt[rand->index] = (6364136223846793005ULL * (rand->mt[rand->index-1] ^ (rand->mt[rand->index-1] >> 62)) + rand->index);
}
}
int64_t genRandLong(MTRand* rand) {
int i;
uint64_t x;
static uint64_t mag01[2] = {0ULL, MATRIX_A};
if (rand->index >= NN) { /* generate NN words at one time */
/* if init_genrand64() has not been called, */
/* a default initial seed is used */
if (rand->index == NN+1)
m_seedRand(rand, 5489ULL);
for (i = 0; i < NN-MM; i++) {
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
rand->mt[i] = rand->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
for (; i < NN-1; i++) {
x = (rand->mt[i] & UM) | (rand->mt[i+1] & LM);
rand->mt[i] = rand->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
x = (rand->mt[NN-1] & UM) | (rand->mt[0] & LM);
rand->mt[NN-1] = rand->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
rand->index = 0;
}
x = rand->mt[rand->index++];
x ^= (x >> 29) & 0x5555555555555555ULL;
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
x ^= (x >> 43);
return (int64_t)(x & 0x000FFFFFFFFFFFFFULL); /* return 52-bit value safe for JS */
}
double genRand(MTRand* rand) {
/* generates a random number on [0,1)-real-interval */
return (genRandLong(rand) >> 11) * (1.0/9007199254740992.0);
}
double rand_range(JSContext *js, double min, double max)
{
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
return genRand(mrand) * (max-min)+min;
}
#define JS_GETNUM(JS,VAL,I,TO,TYPE) { \
JSValue val = JS_GetPropertyUint32(JS,VAL,I); \
TO = js2##TYPE(JS, val); \
@@ -157,33 +96,11 @@ static uint32_t xorshift32(){
return rng_state = x;
}
JSC_CCALL(os_rand,
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
return number2js(js, genRand(mrand));
)
JSC_CCALL(os_randi,
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
return JS_NewInt64(js, genRandLong(mrand));
)
JSC_CCALL(os_srand,
MTRand *mrand = &((cell_rt*)JS_GetContextOpaque(js))->mrand;
m_seedRand(mrand, js2number(js,argv[0]));
)
void ffi_load(JSContext *js)
{
cell_rt *rt = JS_GetContextOpaque(js);
JS_FreeValue(js, js_blob_use(js));
uint64_t rr;
// randombytes is defined in qjs_crypto.c which is linked, but header was removed.
// We declare it here to avoid implicit declaration error.
extern int randombytes(void *buf, size_t n);
randombytes(&rr,4);
m_seedRand(&rt->mrand, rr);
JSValue globalThis = JS_GetGlobalObject(js);
JSValue prosp = JS_NewObject(js);

View File

@@ -538,6 +538,16 @@ void *js_get_blob_data(JSContext *js, size_t *size, JSValue v)
return b->data;
}
void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v)
{
blob *b = js2blob(js, v);
if (!b || !b->is_stone)
return NULL;
*bits = b->length;
return b->data;
}
int js_is_blob(JSContext *js, JSValue v)
{
blob *b = js2blob(js,v);