runtime: add dharma-required functions to el_runtime.c and runtime/*.el

Add the following functions that dharma registry calls but were missing
from the El runtime:

el_runtime.c (consumed by the old build system via released SDK):
  - list_len, list_get — aliases for el_list_len/el_list_get (handlers.el)
  - json_array_push — append pre-encoded element to JSON array string
  - now_millis, unix_timestamp_ms, time_now_ms — ms-since-epoch aliases
  - log_info, log_warn — structured stderr log helpers
  - config — reads config from environment (alias for getenv)
  - http_patch — HTTP PATCH with Content-Type: application/json
  - http_post_engram — HTTP POST with optional X-API-Key header
  - http_get_engram — HTTP GET with optional X-API-Key header
  - str_to_bytes — encode string as JSON byte array [72,101,...]
  - bytes_to_str — decode JSON byte array back to string
  - hash_sha256 — SHA-256 hex digest using built-in sha256 impl

runtime/*.el (consumed by the new build system):
  - http.el: http_patch, http_post_engram, http_get_engram
  - time.el: now_millis, unix_timestamp_ms, time_now_ms
  - env.el: config, log_info, log_warn, list_len, list_get
  - json.el: json_array_push, bytes_to_str
  - string.el: str_to_bytes, hash_sha256 (via __sha256_hex seed)

el_seed.h / el_seed.c:
  - __sha256_hex primitive with self-contained SHA-256 implementation
This commit is contained in:
Will Anderson
2026-05-04 19:07:08 -05:00
parent 245eb2898e
commit 53f2df500d
8 changed files with 580 additions and 0 deletions
+106
View File
@@ -1097,3 +1097,109 @@ el_val_t __engram_list_layers_json(void) { return engram_list_
el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) {
return engram_compile_layered_json(intent, depth);
}
/* ── Cryptographic hashing ────────────────────────────────────────────────── */
/*
* SHA-256 — self-contained implementation (no OpenSSL dependency).
* Based on Brad Conte's public-domain reference implementation.
*/
typedef struct {
uint8_t data[64];
uint32_t datalen;
uint64_t bitlen;
uint32_t state[8];
} _seed_sha256_ctx;
static const uint32_t _seed_sha256_k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
#define _SEED_ROTR32(x,n) (((x)>>(n))|((x)<<(32-(n))))
#define _SEED_CH(x,y,z) (((x)&(y))^(~(x)&(z)))
#define _SEED_MAJ(x,y,z) (((x)&(y))^((x)&(z))^((y)&(z)))
#define _SEED_EP0(x) (_SEED_ROTR32(x,2)^_SEED_ROTR32(x,13)^_SEED_ROTR32(x,22))
#define _SEED_EP1(x) (_SEED_ROTR32(x,6)^_SEED_ROTR32(x,11)^_SEED_ROTR32(x,25))
#define _SEED_SIG0(x) (_SEED_ROTR32(x,7)^_SEED_ROTR32(x,18)^((x)>>3))
#define _SEED_SIG1(x) (_SEED_ROTR32(x,17)^_SEED_ROTR32(x,19)^((x)>>10))
static void _seed_sha256_transform(_seed_sha256_ctx* ctx, const uint8_t* data) {
uint32_t a,b,c,d,e,f,g,h,t1,t2,m[64];
for (int i=0,j=0; i<16; i++,j+=4)
m[i]=(uint32_t)(data[j]<<24)|(data[j+1]<<16)|(data[j+2]<<8)|data[j+3];
for (int i=16; i<64; i++)
m[i]=_SEED_SIG1(m[i-2])+m[i-7]+_SEED_SIG0(m[i-15])+m[i-16];
a=ctx->state[0]; b=ctx->state[1]; c=ctx->state[2]; d=ctx->state[3];
e=ctx->state[4]; f=ctx->state[5]; g=ctx->state[6]; h=ctx->state[7];
for (int i=0; i<64; i++) {
t1=h+_SEED_EP1(e)+_SEED_CH(e,f,g)+_seed_sha256_k[i]+m[i];
t2=_SEED_EP0(a)+_SEED_MAJ(a,b,c);
h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2;
}
ctx->state[0]+=a; ctx->state[1]+=b; ctx->state[2]+=c; ctx->state[3]+=d;
ctx->state[4]+=e; ctx->state[5]+=f; ctx->state[6]+=g; ctx->state[7]+=h;
}
static void _seed_sha256_init(_seed_sha256_ctx* ctx) {
ctx->datalen=0; ctx->bitlen=0;
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;
}
static void _seed_sha256_update(_seed_sha256_ctx* ctx, const uint8_t* data, size_t len) {
for (size_t i=0; i<len; i++) {
ctx->data[ctx->datalen++] = data[i];
if (ctx->datalen==64) { _seed_sha256_transform(ctx,ctx->data); ctx->bitlen+=512; ctx->datalen=0; }
}
}
static void _seed_sha256_final(_seed_sha256_ctx* ctx, uint8_t hash[32]) {
uint32_t i=ctx->datalen;
ctx->data[i++]=0x80;
if (ctx->datalen<56) { while(i<56) ctx->data[i++]=0; }
else { while(i<64) ctx->data[i++]=0; _seed_sha256_transform(ctx,ctx->data); memset(ctx->data,0,56); }
ctx->bitlen+=ctx->datalen*8;
ctx->data[63]=(uint8_t)(ctx->bitlen); ctx->data[62]=(uint8_t)(ctx->bitlen>>8);
ctx->data[61]=(uint8_t)(ctx->bitlen>>16); ctx->data[60]=(uint8_t)(ctx->bitlen>>24);
ctx->data[59]=(uint8_t)(ctx->bitlen>>32); ctx->data[58]=(uint8_t)(ctx->bitlen>>40);
ctx->data[57]=(uint8_t)(ctx->bitlen>>48); ctx->data[56]=(uint8_t)(ctx->bitlen>>56);
_seed_sha256_transform(ctx,ctx->data);
for (i=0; i<4; i++) {
hash[i] =(uint8_t)(ctx->state[0]>>(24-i*8));
hash[i+4] =(uint8_t)(ctx->state[1]>>(24-i*8));
hash[i+8] =(uint8_t)(ctx->state[2]>>(24-i*8));
hash[i+12] =(uint8_t)(ctx->state[3]>>(24-i*8));
hash[i+16] =(uint8_t)(ctx->state[4]>>(24-i*8));
hash[i+20] =(uint8_t)(ctx->state[5]>>(24-i*8));
hash[i+24] =(uint8_t)(ctx->state[6]>>(24-i*8));
hash[i+28] =(uint8_t)(ctx->state[7]>>(24-i*8));
}
}
el_val_t __sha256_hex(el_val_t sv) {
const char* s = EL_CSTR(sv);
if (!s) s = "";
_seed_sha256_ctx ctx;
_seed_sha256_init(&ctx);
_seed_sha256_update(&ctx, (const uint8_t*)s, strlen(s));
uint8_t digest[32];
_seed_sha256_final(&ctx, digest);
static const char hex[] = "0123456789abcdef";
char* out = malloc(65);
if (!out) return EL_STR("");
for (int i=0; i<32; i++) {
out[i*2] = hex[(digest[i]>>4)&0xf];
out[i*2+1] = hex[digest[i]&0xf];
}
out[64] = '\0';
return EL_STR(out);
}