3 Commits
log ... seif

Author SHA1 Message Date
John Alanbrook
f4ea552271 initial try at seif handshake example
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-25 00:07:20 -05:00
John Alanbrook
792da2ce4b Merge remote-tracking branch 'origin/misty'
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-24 22:24:01 -05:00
John Alanbrook
85ee724754 add texture mode for renderer
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-11 09:34:31 -05:00
8 changed files with 609 additions and 7 deletions

50
examples/seif_client.js Normal file
View File

@@ -0,0 +1,50 @@
// Seif Handshake Client Example
// Implements the Seif Protocol handshake client side
var crypto = use('crypto');
var json = use('json');
var io = use('io');
// Alice's key pair
var alice_keys = crypto.keypair();
console.log("Alice public key:", alice_keys.public);
console.log("Alice private key:", alice_keys.private);
// Bob's public key (in real usage, this would be obtained separately)
// For this example, we'll use a hardcoded key or read from file
var bob_public_key = null;
// Try to read Bob's public key from file if it exists
if (io.exists('bob_public.key')) {
bob_public_key = io.slurp('bob_public.key').trim();
console.log("Loaded Bob's public key from file:", bob_public_key);
} else {
// For testing, use the server's public key printed by seif_server.js
console.log("Please create bob_public.key with the server's public key");
console.log("Run seif_server.js first to get the public key");
return;
}
// Generate random handshake key
var handshake_key = crypto.keypair().public; // Using public key as random 32-byte value
console.log("Generated handshake key:", handshake_key);
console.log("Sending handshake to server...");
// Contact the server
$_.contact((actor, reason) => {
if (!actor) {
console.error("Could not establish connection:", reason);
return;
}
}, {
address: "localhost",
port: 5678,
seif: 1,
handshake: crypto.encrypt_pk(bob_public_key, handshake_key),
payload: crypto.encrypt(handshake_key, alice_keys.public)
});
$_.receiver(e => {
console.log("Received message:", e);
});

View File

@@ -0,0 +1,83 @@
# Seif Handshake Examples
This directory contains examples demonstrating the Seif Protocol handshake implementation in Prosperon.
## Files
- `seif_simple.js` - A standalone demonstration of the Seif handshake cryptographic operations
- `seif_server.js` - A server that accepts Seif handshake connections
- `seif_client.js` - A client that initiates Seif handshake with a server
## Running the Examples
### Simple Demo
To see the cryptographic operations in action:
```bash
./prosperon examples/seif_simple.js
```
### Client-Server Demo
1. First, start the server:
```bash
./prosperon examples/seif_server.js
```
2. Note the server's public key that is printed
3. Create a file `bob_public.key` with the server's public key:
```bash
echo "SERVER_PUBLIC_KEY_HERE" > bob_public.key
```
4. In another terminal, run the client:
```bash
./prosperon examples/seif_client.js
```
## The Seif Protocol
The Seif handshake establishes a secure session in one round trip:
1. **Alice's Message**:
- Generates random `handshake_key`
- Sends: `{seif: 1, handshake: encrypt_pk(bob_public, handshake_key), payload: encrypt(handshake_key, alice_public)}`
2. **Bob's Response**:
- Decrypts `handshake_key` using his private key
- Decrypts Alice's public key from payload
- Generates `session_key`
- Sends: `encrypt(handshake_key, {session: encrypt_pk(alice_public, session_key)})`
3. **Result**: Both parties share `session_key` for symmetric encryption
## Actor System Integration
In Prosperon's actor system:
- Actor objects can serve as public key identifiers (they contain unique IDs)
- The `$_.portal()` function creates a listening endpoint
- The `$_.contact()` function initiates connections
- Messages are automatically routed through the actor system
## Security Properties
- **Authentication**: Both parties prove possession of their private keys
- **Forward Secrecy**: Session keys are ephemeral
- **Man-in-the-Middle Protection**: Requires knowledge of both private keys
- **One Round Trip**: Efficient session establishment
## Notes on Implementation
The current implementation uses the actor object's ID as part of the identity system. In a production system, you might want to:
1. Store the public key as part of the actor's data
2. Use a proper key derivation function for session keys
3. Add additional metadata in the handshake (timestamps, nonces, etc.)
4. Implement key rotation and session management
The crypto module provides:
- `crypto.keypair()` - Generate X25519 key pairs
- `crypto.encrypt_pk(public_key, data)` - Public key encryption
- `crypto.decrypt_pk(private_key, data)` - Public key decryption
- `crypto.encrypt(key, data)` - Symmetric encryption
- `crypto.decrypt(key, data)` - Symmetric decryption

85
examples/seif_server.js Normal file
View File

@@ -0,0 +1,85 @@
// Seif Handshake Server Example
// Implements the Seif Protocol handshake as described in the documentation
var crypto = use('crypto');
var json = use('json');
var io = use('io');
// Server's key pair
var server_keys = crypto.keypair();
console.log("Server public key:", server_keys.public);
console.log("Server private key:", server_keys.private);
// Store connected clients
var clients = {};
$_.portal(e => {
// Verify the handshake message format
if (!e.seif || !e.handshake || !e.payload) {
send(e, {error:"Invalid Seif handshake format"});
return;
}
if (e.seif !== 1) {
send(e, {error:"Unsupported Seif protocol version:", e.seif});
return;
}
try {
// Decrypt the handshake key with server's private key
var handshake_key_encrypted = e.handshake;
var handshake_key_hex = crypto.decrypt_pk(server_keys.private, handshake_key_encrypted);
// Convert ArrayBuffer to hex string
var handshake_key_bytes = new Uint8Array(handshake_key_hex);
var handshake_key = '';
for (var i = 0; i < handshake_key_bytes.length; i++) {
var hex = handshake_key_bytes[i].toString(16);
handshake_key += (hex.length === 1 ? '0' : '') + hex;
}
console.log("Decrypted handshake key:", handshake_key);
// Decrypt the payload (client's public key) with handshake key
var client_public_encrypted = e.payload;
var client_public_buffer = crypto.decrypt(handshake_key, client_public_encrypted);
// Convert decrypted buffer to string
var client_public_bytes = new Uint8Array(client_public_buffer);
var client_public = '';
for (var i = 0; i < client_public_bytes.length; i++) {
client_public += String.fromCharCode(client_public_bytes[i]);
}
console.log("Client's public key:", client_public);
// Generate session key
var session_key = crypto.keypair();
console.log("Generated session key:", session_key.public);
// Create response encrypted with handshake key
var response = {
session: crypto.encrypt_pk(client_public, session_key.public)
};
var response_encrypted = crypto.encrypt(handshake_key, json.encode(response));
// Send encrypted response
send(e, response_encrypted);
console.log("Handshake complete with client:", client_public);
} catch (err) {
send(e, {error:err})
}
}, 5678);
// Handle messages from connected clients
$_.receiver(e => {
if (e.type === 'encrypted_message') {
console.log("Received encrypted message");
// In a real implementation, decrypt with session key and process
}
});
console.log("Seif server listening on port 5678");

118
examples/seif_simple.js Normal file
View File

@@ -0,0 +1,118 @@
// Simplified Seif Handshake Example
// This demonstrates the core cryptographic operations of the Seif handshake
var crypto = use('crypto');
var json = use('json');
console.log("=== Seif Handshake Demo ===\n");
// Step 1: Generate key pairs for Alice and Bob
console.log("1. Generating key pairs...");
var alice_keys = crypto.keypair();
var bob_keys = crypto.keypair();
console.log("Alice's public key:", alice_keys.public);
console.log("Bob's public key:", bob_keys.public);
// Step 2: Alice initiates handshake
console.log("\n2. Alice initiates handshake...");
// Alice generates a random handshake key
var handshake_key = crypto.keypair().public; // Using public key generation for random 32 bytes
console.log("Handshake key:", handshake_key);
// Alice creates the handshake message
var alice_message = {
seif: 1,
handshake: crypto.encrypt_pk(bob_keys.public, handshake_key),
payload: crypto.encrypt(handshake_key, alice_keys.public)
};
console.log("Alice's message created (encrypted components)");
// Step 3: Bob processes the handshake
console.log("\n3. Bob processes the handshake...");
// Bob decrypts the handshake key
var decrypted_handshake_key_buffer = crypto.decrypt_pk(bob_keys.private, alice_message.handshake);
// Convert buffer to hex string
var handshake_key_bytes = new Uint8Array(decrypted_handshake_key_buffer);
var recovered_handshake_key = '';
for (var i = 0; i < handshake_key_bytes.length; i++) {
var hex = handshake_key_bytes[i].toString(16);
recovered_handshake_key += (hex.length === 1 ? '0' : '') + hex;
}
console.log("Bob recovered handshake key:", recovered_handshake_key);
console.log("Keys match:", recovered_handshake_key === handshake_key);
// Bob decrypts Alice's public key
var alice_public_buffer = crypto.decrypt(recovered_handshake_key, alice_message.payload);
var alice_public_bytes = new Uint8Array(alice_public_buffer);
var recovered_alice_public = '';
for (var i = 0; i < alice_public_bytes.length; i++) {
recovered_alice_public += String.fromCharCode(alice_public_bytes[i]);
}
console.log("Bob recovered Alice's public key:", recovered_alice_public);
console.log("Public keys match:", recovered_alice_public === alice_keys.public);
// Step 4: Bob generates session key and responds
console.log("\n4. Bob generates session key and responds...");
// Generate a random session key
var session_key = crypto.keypair().public;
console.log("Session key:", session_key);
// Bob encrypts the session key with Alice's public key
var bob_response = {
session: crypto.encrypt_pk(alice_keys.public, session_key)
};
// Encrypt the entire response with the handshake key
var encrypted_response = crypto.encrypt(handshake_key, json.encode(bob_response));
console.log("Bob's encrypted response created");
// Step 5: Alice processes Bob's response
console.log("\n5. Alice processes Bob's response...");
// Alice decrypts the response
var decrypted_response_buffer = crypto.decrypt(handshake_key, encrypted_response);
var response_json = '';
var response_bytes = new Uint8Array(decrypted_response_buffer);
for (var i = 0; i < response_bytes.length; i++) {
response_json += String.fromCharCode(response_bytes[i]);
}
var response_data = json.decode(response_json);
// Alice decrypts the session key
var session_key_buffer = crypto.decrypt_pk(alice_keys.private, response_data.session);
var session_key_bytes = new Uint8Array(session_key_buffer);
var recovered_session_key = '';
for (var i = 0; i < session_key_bytes.length; i++) {
var hex = session_key_bytes[i].toString(16);
recovered_session_key += (hex.length === 1 ? '0' : '') + hex;
}
console.log("Alice recovered session key:", recovered_session_key);
console.log("Session keys match:", recovered_session_key === session_key);
// Step 6: Demonstrate secure communication
console.log("\n6. Secure communication established!");
console.log("Both parties now share the session key and can communicate securely.");
// Example encrypted message
var message = "Hello, this is a secret message!";
var encrypted_msg = crypto.encrypt(session_key, message);
console.log("\nAlice encrypts:", message);
var decrypted_msg_buffer = crypto.decrypt(session_key, encrypted_msg);
var decrypted_msg = '';
var msg_bytes = new Uint8Array(decrypted_msg_buffer);
for (var i = 0; i < msg_bytes.length; i++) {
decrypted_msg += String.fromCharCode(msg_bytes[i]);
}
console.log("Bob decrypts:", decrypted_msg);
console.log("\n=== Seif Handshake Complete ===");

View File

@@ -406,9 +406,10 @@ var image_info = {
flip_x: false,
flip_y: false,
color: Color.white,
mode: 'linear'
}
draw.image = function image(image, rect = [0,0], rotation = 0, anchor = [0,0], shear = [0,0], info, pipeline) {
draw.image = function image(image, rect = [0,0], rotation = 0, anchor = [0,0], shear = [0,0], info = {}, pipeline) {
if (!image) throw Error('Need an image to render.')
if (typeof image === "string")
image = graphics.texture(image)

View File

@@ -28,8 +28,10 @@ render.initialize = function(config)
url: "https://prosperon.dev"
}
prosperon.window = prosperon.engine_start({width:500,height:500})
context = prosperon.window.make_renderer("vulkan")
config.__proto__ = default_conf
prosperon.window = prosperon.engine_start(config)
context = prosperon.window.make_renderer()
context.logical_size([config.resolution_x, config.resolution_y], config.mode)
}
render.sprite = function(sprite)
@@ -49,6 +51,7 @@ render.image = function(image, rect, rotation, anchor, shear, info)
{
// rect.width = image.rect_px.width;
// rect.height = image.rect_px.height;
image.texture.mode(info.mode)
context.texture(image.texture, image.rect_px, rect, rotation, anchor);
}

View File

@@ -1466,10 +1466,41 @@ JSC_CCALL(renderer_geometry2,
JS_FreeValue(js, idx_v);
)
/* logical presentation helpers */
typedef struct { const char *name; SDL_RendererLogicalPresentation pres; } pres_entry;
static const pres_entry k_pres_table[] = {
{ "stretch", SDL_LOGICAL_PRESENTATION_STRETCH },
{ "letterbox", SDL_LOGICAL_PRESENTATION_LETTERBOX },
{ "overscan", SDL_LOGICAL_PRESENTATION_OVERSCAN },
{ "integer", SDL_LOGICAL_PRESENTATION_INTEGER_SCALE },
{ NULL, SDL_LOGICAL_PRESENTATION_DISABLED } /* fallback */
};
static JSValue logicalpresentation2js(JSContext *js,
SDL_RendererLogicalPresentation pres){
const pres_entry *it;
for(it = k_pres_table; it->name; ++it)
if(it->pres == pres) break;
return JS_NewString(js, it->name ? it->name : "disabled");
}
static SDL_RendererLogicalPresentation
js2SDL_LogicalPresentation(JSContext *js, JSValue v){
if(JS_IsUndefined(v)) return SDL_LOGICAL_PRESENTATION_DISABLED;
const char *s = JS_ToCString(js, v);
if(!s) return SDL_LOGICAL_PRESENTATION_DISABLED;
const pres_entry *it;
for(it = k_pres_table; it->name; ++it)
if(!strcmp(it->name, s)) break;
JS_FreeCString(js, s);
return it->pres;
}
JSC_CCALL(renderer_logical_size,
SDL_Renderer *r = js2renderer_ctx(js,self)->sdl;
HMM_Vec2 v = js2vec2(js,argv[0]);
SDL_SetRenderLogicalPresentation(r,v.x,v.y,SDL_LOGICAL_PRESENTATION_INTEGER_SCALE);
SDL_SetRenderLogicalPresentation(r,v.x,v.y,js2SDL_LogicalPresentation(js, argv[1]));
)
JSC_CCALL(renderer_viewport,
@@ -1663,7 +1694,7 @@ static const JSCFunctionListEntry js_renderer_ctx_funcs[] = {
MIST_FUNC_DEF(renderer, get_image, 1),
MIST_FUNC_DEF(renderer, scale, 1),
MIST_FUNC_DEF(renderer, logical_size,1),
MIST_FUNC_DEF(renderer, logical_size,2),
MIST_FUNC_DEF(renderer, viewport,1),
MIST_FUNC_DEF(renderer, clip,1),
MIST_FUNC_DEF(renderer, vsync,1),
@@ -1894,7 +1925,8 @@ static const JSCFunctionListEntry js_SDL_Surface_funcs[] = {
JSC_CCALL(texture_mode,
SDL_Texture *tex = js2SDL_Texture(js,self);
SDL_SetTextureScaleMode(tex,js2number(js,argv[0]));
SDL_ScaleMode mode = js2SDL_ScaleMode(js,argv[0]);
SDL_SetTextureScaleMode(tex,mode);
)
static const JSCFunctionListEntry js_SDL_Texture_funcs[] = {

View File

@@ -199,10 +199,240 @@ JSValue js_crypto_random(JSContext *js, JSValue self, int argc, JSValue *argv)
return JS_NewFloat64(js, val);
}
JSValue js_crypto_encrypt_pk(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.encrypt_pk: expected 2 arguments (public_key, plaintext)");
}
uint8_t public_key[32];
js2crypto(js, argv[0], public_key);
size_t plaintext_len;
uint8_t *plaintext;
if (JS_IsString(argv[1])) {
const char *str = JS_ToCStringLen(js, &plaintext_len, argv[1]);
if (!str) return JS_EXCEPTION;
plaintext = (uint8_t *)str;
} else {
plaintext = JS_GetArrayBuffer(js, &plaintext_len, argv[1]);
if (!plaintext) {
return JS_ThrowTypeError(js, "crypto.encrypt_pk: plaintext must be string or ArrayBuffer");
}
}
// Generate ephemeral keypair
uint8_t ephemeral_secret[32];
uint8_t ephemeral_public[32];
randombytes(ephemeral_secret, 32);
ephemeral_secret[0] &= 248;
ephemeral_secret[31] &= 127;
ephemeral_secret[31] |= 64;
crypto_x25519_public_key(ephemeral_public, ephemeral_secret);
// Compute shared secret
uint8_t shared[32];
crypto_x25519(shared, ephemeral_secret, public_key);
// Derive encryption key using BLAKE2b
uint8_t key[32];
crypto_blake2b(key, 32, shared, 32);
// Generate random nonce
uint8_t nonce[24];
randombytes(nonce, 24);
// Allocate output buffer: ephemeral_public(32) + nonce(24) + ciphertext + mac(16)
size_t output_size = 32 + 24 + plaintext_len + 16;
uint8_t *output = js_malloc(js, output_size);
if (!output) {
if (JS_IsString(argv[1])) JS_FreeCString(js, (const char *)plaintext);
return JS_EXCEPTION;
}
// Copy ephemeral public key and nonce to output
memcpy(output, ephemeral_public, 32);
memcpy(output + 32, nonce, 24);
// Encrypt
crypto_aead_lock(output + 32 + 24, output + 32 + 24 + plaintext_len,
key, nonce, NULL, 0, plaintext, plaintext_len);
if (JS_IsString(argv[1])) JS_FreeCString(js, (const char *)plaintext);
// Wipe sensitive data
crypto_wipe(ephemeral_secret, 32);
crypto_wipe(shared, 32);
crypto_wipe(key, 32);
JSValue result = JS_NewArrayBufferCopy(js, output, output_size);
js_free(js, output);
return result;
}
JSValue js_crypto_decrypt_pk(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.decrypt_pk: expected 2 arguments (private_key, ciphertext)");
}
uint8_t private_key[32];
js2crypto(js, argv[0], private_key);
size_t ciphertext_len;
uint8_t *ciphertext = JS_GetArrayBuffer(js, &ciphertext_len, argv[1]);
if (!ciphertext) {
return JS_ThrowTypeError(js, "crypto.decrypt_pk: ciphertext must be ArrayBuffer");
}
if (ciphertext_len < 32 + 24 + 16) {
return JS_ThrowTypeError(js, "crypto.decrypt_pk: ciphertext too short");
}
// Extract ephemeral public key and nonce
uint8_t ephemeral_public[32];
uint8_t nonce[24];
memcpy(ephemeral_public, ciphertext, 32);
memcpy(nonce, ciphertext + 32, 24);
// Compute shared secret
uint8_t shared[32];
crypto_x25519(shared, private_key, ephemeral_public);
// Derive decryption key
uint8_t key[32];
crypto_blake2b(key, 32, shared, 32);
// Decrypt
size_t plaintext_len = ciphertext_len - 32 - 24 - 16;
uint8_t *plaintext = js_malloc(js, plaintext_len);
if (!plaintext) {
crypto_wipe(shared, 32);
crypto_wipe(key, 32);
return JS_EXCEPTION;
}
int result = crypto_aead_unlock(plaintext,
ciphertext + ciphertext_len - 16,
key, nonce, NULL, 0,
ciphertext + 32 + 24, plaintext_len);
crypto_wipe(shared, 32);
crypto_wipe(key, 32);
if (result != 0) {
js_free(js, plaintext);
return JS_ThrowTypeError(js, "crypto.decrypt_pk: decryption failed");
}
JSValue ret = JS_NewArrayBufferCopy(js, plaintext, plaintext_len);
js_free(js, plaintext);
return ret;
}
JSValue js_crypto_encrypt(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.encrypt: expected 2 arguments (key, plaintext)");
}
uint8_t key[32];
js2crypto(js, argv[0], key);
size_t plaintext_len;
uint8_t *plaintext;
if (JS_IsString(argv[1])) {
const char *str = JS_ToCStringLen(js, &plaintext_len, argv[1]);
if (!str) return JS_EXCEPTION;
plaintext = (uint8_t *)str;
} else {
plaintext = JS_GetArrayBuffer(js, &plaintext_len, argv[1]);
if (!plaintext) {
return JS_ThrowTypeError(js, "crypto.encrypt: plaintext must be string or ArrayBuffer");
}
}
// Generate random nonce
uint8_t nonce[24];
randombytes(nonce, 24);
// Allocate output buffer: nonce(24) + ciphertext + mac(16)
size_t output_size = 24 + plaintext_len + 16;
uint8_t *output = js_malloc(js, output_size);
if (!output) {
if (JS_IsString(argv[1])) JS_FreeCString(js, (const char *)plaintext);
return JS_EXCEPTION;
}
// Copy nonce to output
memcpy(output, nonce, 24);
// Encrypt
crypto_aead_lock(output + 24, output + 24 + plaintext_len,
key, nonce, NULL, 0, plaintext, plaintext_len);
if (JS_IsString(argv[1])) JS_FreeCString(js, (const char *)plaintext);
JSValue result = JS_NewArrayBufferCopy(js, output, output_size);
js_free(js, output);
return result;
}
JSValue js_crypto_decrypt(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.decrypt: expected 2 arguments (key, ciphertext)");
}
uint8_t key[32];
js2crypto(js, argv[0], key);
size_t ciphertext_len;
uint8_t *ciphertext = JS_GetArrayBuffer(js, &ciphertext_len, argv[1]);
if (!ciphertext) {
return JS_ThrowTypeError(js, "crypto.decrypt: ciphertext must be ArrayBuffer");
}
if (ciphertext_len < 24 + 16) {
return JS_ThrowTypeError(js, "crypto.decrypt: ciphertext too short");
}
// Extract nonce
uint8_t nonce[24];
memcpy(nonce, ciphertext, 24);
// Decrypt
size_t plaintext_len = ciphertext_len - 24 - 16;
uint8_t *plaintext = js_malloc(js, plaintext_len);
if (!plaintext) {
return JS_EXCEPTION;
}
int result = crypto_aead_unlock(plaintext,
ciphertext + ciphertext_len - 16,
key, nonce, NULL, 0,
ciphertext + 24, plaintext_len);
if (result != 0) {
js_free(js, plaintext);
return JS_ThrowTypeError(js, "crypto.decrypt: decryption failed");
}
JSValue ret = JS_NewArrayBufferCopy(js, plaintext, plaintext_len);
js_free(js, plaintext);
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("random", 0, js_crypto_random),
JS_CFUNC_DEF("encrypt_pk", 2, js_crypto_encrypt_pk),
JS_CFUNC_DEF("decrypt_pk", 2, js_crypto_decrypt_pk),
JS_CFUNC_DEF("encrypt", 2, js_crypto_encrypt),
JS_CFUNC_DEF("decrypt", 2, js_crypto_decrypt),
};
JSValue js_crypto_use(JSContext *js)