checkpoint

This commit is contained in:
Simon Arnell 2025-01-27 19:43:01 +02:00
parent 00184ff68a
commit af465dfcfa
2 changed files with 179 additions and 701 deletions

View file

@ -10,7 +10,7 @@
import Operation from "../Operation.mjs";
import * as hydro from "libhydrogen/libHydrogen.js";
import * as hydro from "@configuredthings/libhydrogen-wasm/libHydrogen.js";
/**
* LibHydrogen Curve25519 Sign operation
@ -27,190 +27,182 @@ class LibHydrogenCurve25519Signing extends Operation {
this.module = "Crypto";
this.description = "Computes a signature for a message using the lightweight LibHydrogen cryptography library";
this.infoURL = "https://libhydrogen.org/";
this.inputType = "byteArray";
this.inputType = "JSON";
this.outputType = "JSON";
this.args = [
{
name: "First arg",
name: "Context",
type: "string",
value: "Don't Panic"
value: ""
},
{
name: "Second arg",
type: "number",
value: 42
name: "Sender's private key",
type: "byteArray",
value: ""
}
];
}
/**
* @param {byteArray} input
* @param {JSON} input
* @param {Object[]} args
* @returns {JSON}
*/
run(input, args) {
const [firstArg, secondArg] = args;
(async () => {
const wasm_src = await fetch(new URL(`${self.docURL}/assets/libhydrogen/libhydrogen.wasm`));
const wasm = await WebAssembly.compileStreaming(wasm_src);
const imports = {
"wasi_snapshot_preview1": {
args_get() {
return 0;
},
args_sizes_get() {
return 0;
},
clock_res_get() {
return 0;
},
clock_time_get() {
return 0;
},
environ_sizes_get() {
return 0;
},
environ_get() {
return 0;
},
proc_exit() {
return 0;
},
fd_write() {
return 0;
},
fd_advise() {
return 0;
},
fd_allocate() {
return 0;
},
fd_close() {
return 0;
},
fd_datasync() {
return 0;
},
fd_fdstat_get() {
return 0;
},
fd_fdstat_set_flags() {
return 0;
},
fd_fdstat_set_rights() {
return 0;
},
fd_filestat_get() {
return 0;
},
fd_filestat_set_size() {
return 0;
},
fd_filestat_set_times() {
return 0;
},
fd_pread() {
return 0;
},
fd_prestat_get() {
return 0;
},
fd_prestat_dir_name() {
return 0;
},
fd_pwrite() {
return 0;
},
fd_read() {
return 0;
},
fd_readdir() {
return 0;
},
fd_renumber() {
return 0;
},
fd_seek() {
return 0;
},
fd_sync() {
return 0;
},
fd_tell() {
return 0;
},
path_create_directory() {
return 0;
},
path_filestat_get() {
return 0;
},
path_filestat_set_times() {
return 0;
},
path_link() {
return 0;
},
path_open() {
return 0;
},
path_readlink() {
return 0;
},
path_remove_directory() {
return 0;
},
path_rename() {
return 0;
},
path_symlink() {
return 0;
},
path_unlink_file() {
return 0;
},
poll_oneoff() {
return 0;
},
sched_yield() {
return 0;
},
random_get(buf, buf_len) {
const random_arr = new Uint8Array(dataview.buffer, buf, buf_len);
crypto.getRandomValues(random_arr);
return 0;
},
sock_accept() {
return 0;
},
sock_recv() {
return 0;
},
sock_send() {
return 0;
},
sock_shutdown() {
return 0;
},
}
};
instance = await WebAssembly.instantiate(wasm, imports);
// Get the memory are used as a stack when calling into the WASI
const memory = instance.exports.memory;
// DataView takes care of our platform specific endian conversions
dataview = new DataView(memory.buffer);
// We must call a start method per WASI specification
// Libhydrogen's main method is one we have patched to initialise it
instance.exports._start();
// Run the various examples
random_uniform();
hash();
keyed_hash();
public_key_signing();
symmetric_encryption();
symmetric_encryption_via_asymmetric_key_exchange();
})();
return {};
async run(input, args) {
const [context, privateKey] = args;
const wasm_src = await fetch(new URL(`${self.docURL}/assets/libhydrogen-wasm/libhydrogen.wasm`));
const wasm = await WebAssembly.compileStreaming(wasm_src);
const imports = {
"wasi_snapshot_preview1": {
args_get() {
return 0;
},
args_sizes_get() {
return 0;
},
clock_res_get() {
return 0;
},
clock_time_get() {
return 0;
},
environ_sizes_get() {
return 0;
},
environ_get() {
return 0;
},
proc_exit() {
return 0;
},
fd_write() {
return 0;
},
fd_advise() {
return 0;
},
fd_allocate() {
return 0;
},
fd_close() {
return 0;
},
fd_datasync() {
return 0;
},
fd_fdstat_get() {
return 0;
},
fd_fdstat_set_flags() {
return 0;
},
fd_fdstat_set_rights() {
return 0;
},
fd_filestat_get() {
return 0;
},
fd_filestat_set_size() {
return 0;
},
fd_filestat_set_times() {
return 0;
},
fd_pread() {
return 0;
},
fd_prestat_get() {
return 0;
},
fd_prestat_dir_name() {
return 0;
},
fd_pwrite() {
return 0;
},
fd_read() {
return 0;
},
fd_readdir() {
return 0;
},
fd_renumber() {
return 0;
},
fd_seek() {
return 0;
},
fd_sync() {
return 0;
},
fd_tell() {
return 0;
},
path_create_directory() {
return 0;
},
path_filestat_get() {
return 0;
},
path_filestat_set_times() {
return 0;
},
path_link() {
return 0;
},
path_open() {
return 0;
},
path_readlink() {
return 0;
},
path_remove_directory() {
return 0;
},
path_rename() {
return 0;
},
path_symlink() {
return 0;
},
path_unlink_file() {
return 0;
},
poll_oneoff() {
return 0;
},
sched_yield() {
return 0;
},
random_get(buf, buf_len) {
const random_arr = new Uint8Array(dataview.buffer, buf, buf_len);
crypto.getRandomValues(random_arr);
return 0;
},
sock_accept() {
return 0;
},
sock_recv() {
return 0;
},
sock_send() {
return 0;
},
sock_shutdown() {
return 0;
},
}
};
instance = await WebAssembly.instantiate(wasm, imports);
// Get the memory are used as a stack when calling into the WASI
const memory = instance.exports.memory;
// DataView takes care of our platform specific endian conversions
dataview = new DataView(memory.buffer);
// We must call a start method per WASI specification
// Libhydrogen's main method is one we have patched to initialise it
instance.exports._start();
// Generated signature for JSON input
return await sign(input, context, privateKey);
}
}
@ -219,7 +211,7 @@ let instance, dataview;
//
// Helper function to reserve space in the buffer used
// as a stack between Node and the wasm.
// as a stack between js and the wasm.
//
// Offset must be an an object so we can update it's value
// {value: n}
@ -238,182 +230,10 @@ function reserve(offset, length) {
return a;
}
//
// Generate a series of random numbers
//
function random_uniform() {
console.log("\n=== random_uniform ===\n");
const { hydro_random_uniform } = instance.exports;
// Testing a simple case of passing integers and fetching integers
console.log(`generated random - ${hydro_random_uniform(20)}`);
console.log(`generated random - ${hydro_random_uniform(20)}`);
console.log(`generated random - ${hydro_random_uniform(20)}`);
console.log(`generated random - ${hydro_random_uniform(20)}`);
console.log(`generated random - ${hydro_random_uniform(20)}`);
}
//
// Hash Generation
//
function hash() {
console.log("\n=== hash ===\n");
const { hydro_hash_hash } = instance.exports;
const textEncoder = new TextEncoder();
// We have to create the stack frame to pass to libHydrogen
// in the dataview Buffer, and then pass in pointers to
// that buffer
const offset = { value: 0 };
const context_str = "Examples";
const context_arr = reserve(offset, hydro.hash_CONTEXTBYTES);
const examples_ab = textEncoder.encode(context_str);
for (let i = 0; i < hydro.hash_CONTEXTBYTES; i++) {
context_arr.set([examples_ab.at(i)], i);
}
// Our message to be hashed
const message_str = "Arbitrary data to hash";
const message_ab = textEncoder.encode(message_str);
const message_arr = reserve(offset, message_ab.length);
for (let i = 0; i < message_ab.length; i++) {
message_arr.set([message_ab.at(i)], i);
}
// Buffer for libHydrogen to write the hash into
const hash = reserve(offset, hydro.hash_BYTES);
// Call the imported function
hydro_hash_hash(
hash.byteOffset,
hash.length,
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
null,
);
console.log(`generated hash - ${Buffer.from(hash).toString("hex")}`);
}
//
// Hash generation with a key
//
function keyed_hash() {
console.log("\n=== keyed_hash ===\n");
// Importing libhydrogen's hashing keygen and hash functions
const { hydro_hash_keygen, hydro_hash_hash } = instance.exports;
const textEncoder = new TextEncoder();
// We have to create the stack frame to pass to libHydrogen
// in the dataview Buffer, and then pass in pointers to
// that buffer
const offset = { value: 0 };
const context_str = "Examples";
const context_arr = reserve(offset, hydro.hash_CONTEXTBYTES);
const examples_ab = textEncoder.encode(context_str);
for (let i = 0; i < hydro.hash_CONTEXTBYTES; i++) {
context_arr.set([examples_ab.at(i)], i);
}
const message_str = "Arbitrary data to hash";
const message_ab = textEncoder.encode(message_str);
const message_arr = reserve(offset, message_ab.length);
for (let i = 0; i < message_ab.length; i++) {
message_arr.set([message_ab.at(i)], i);
}
// Reserve buffer space for the returned key
const key = reserve(offset, hydro.hash_KEYBYTES);
// Reserve space for the hash result
const keyedhash = reserve(offset, hydro.hash_BYTES);
// Generate hashing key
hydro_hash_keygen(key.byteOffset);
console.log(`generated hash key - ${key}`);
// Create a hash with the key
hydro_hash_hash(
keyedhash.byteOffset,
keyedhash.length,
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
key.byteOffset,
);
const khash1 = keyedhash.toString("hex");
console.log(`khash1 - ${khash1}`);
keyedhash.fill(0); // Resetting output buffer (seems to pollute state otherwise)
// Hashing message with key again
hydro_hash_hash(
keyedhash.byteOffset,
keyedhash.length,
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
key.byteOffset,
);
const khash2 = keyedhash.toString("hex");
console.log(`khash2 - ${khash2}`);
keyedhash.fill(0);
console.log(`${keyedhash.toString("hex")}`);
// Check that the same hash is generated
if (khash1 === khash2) console.log("khash1 equals khash2");
// Testing whether we can load a key and generate a matching hash created previously
const presetKey = "f539065185b3ce774b0c748564e804a3717ca7d0c08231076e8b7920814f0bba";
console.log(`presetKey - ${presetKey}`);
const historicHash = "4004516ceff97883804dbdb221baeb7283256e60165d0715d0152e4d6a6cbad4";
console.log(`historicHash - ${historicHash}`);
const loadedKey = new Uint8Array(presetKey.match(/../g).map(h=>parseInt(h, 16)));
for (let i = 0; i < loadedKey.length; i++) {
key.set([loadedKey.at(i)], i);
}
// Hashing message with presetKey
hydro_hash_hash(
keyedhash.byteOffset,
keyedhash.length,
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
key.byteOffset,
);
const khash3 = keyedhash.toString("hex");
console.log(`khash3 - ${khash3}`);
// Testing hash matches historicHash
if (khash3 === historicHash)
console.log("khash3 using old key, matches historicHash");
// ...and doesn't match the hashes with the latest key
if (khash1 !== khash3)
console.log("khash3 does not equal khash1");
// clear the buffer for the next example
context_arr.fill(0);
message_arr.fill(0);
keyedhash.fill(0);
key.fill(0);
}
//
// Public key signing
//
function public_key_signing() {
console.log("\n=== public_key_signing ===\n");
async function sign(input, context, privateKey) {
// Importing libhydrogen's signing keygen and signing and verification functions
const { hydro_sign_keygen, hydro_sign_create, hydro_sign_verify } = instance.exports;
const textEncoder = new TextEncoder();
@ -422,16 +242,14 @@ function public_key_signing() {
// in the dataview Buffer, and then pass in pointers to
// that buffer
const offset = { value: 0 };
const context_str = "Examples";
const context_arr = reserve(offset, hydro.hash_CONTEXTBYTES);
const examples_ab = textEncoder.encode(context_str);
const context_ab = textEncoder.encode(context);
for (let i = 0; i < hydro.hash_CONTEXTBYTES; i++) {
context_arr.set([examples_ab.at(i)], i);
context_arr.set([context_ab.at(i)], i);
}
const message_str = "Arbitrary data to hash";
const message_ab = textEncoder.encode(message_str);
const message_ab = textEncoder.encode(JSON.stringify(input));
const message_arr = reserve(offset, message_ab.length);
for (let i = 0; i < message_ab.length; i++) {
@ -439,10 +257,10 @@ function public_key_signing() {
}
// Generate a key pair
const keypair = reserve(offset, hydro.sign_PUBLICKEYBYTES + hydro.sign_SECRETKEYBYTES);
const publicKeyOffset = keypair.byteOffset;
const privateKeyOffset = keypair.byteOffset + hydro.sign_PUBLICKEYBYTES;
hydro_sign_keygen(keypair.byteOffset);
const privateKey_arr = reserve(offset, hydro.sign_SECRETKEYBYTES);
for (let i = 0; i < privateKey.length; i++) {
privateKey_arr.set([privateKey.at(i)], i);
}
// Reserving memory for the signature
const signature = reserve(offset, hydro.sign_BYTES);
@ -453,356 +271,16 @@ function public_key_signing() {
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
privateKeyOffset,
privateKey_arr.byteOffset,
);
console.log(`generated signature - ${Buffer.from(signature).toString("hex")}`);
// Verifying signature with public key
const res = hydro_sign_verify(
signature.byteOffset,
message_arr.byteOffset,
message_arr.byteLength,
context_arr.byteOffset,
publicKeyOffset,
);
if (res === 0) console.log("Signature is correctly valid");
signature.set([0]); // Modifying signature
console.log(`modified signature - ${Buffer.from(signature).toString("hex")}`);
const manipulatedRes = hydro_sign_verify(
signature.byteOffset,
message_arr.byteOffset, // Reverifying signature
message_arr.byteLength,
context_arr.byteOffset,
publicKeyOffset,
);
if (manipulatedRes !== 0) console.log("Signature is correctly invalid");
message_arr.fill(0);
keypair.fill(0);
signature.fill(0);
}
//
// Secret Key Encryption
//
function symmetric_encryption() {
console.log("\n=== symmetric_encryption ===\n");
// Importing libhydrogen's secretbox keygen and encrypt and decrypt functions
const { hydro_secretbox_keygen, hydro_secretbox_encrypt, hydro_secretbox_decrypt } =
instance.exports;
const textEncoder = new TextEncoder();
// We have to create the stack frame to pass to libHydrogen
// in the dataview Buffer, and then pass in pointers to
// that buffer
const offset = { value: 0 };
const context_str = "Examples";
const context_arr = reserve(offset, hydro.hash_CONTEXTBYTES);
const examples_ab = textEncoder.encode(context_str);
for (let i = 0; i < hydro.hash_CONTEXTBYTES; i++) {
context_arr.set([examples_ab.at(i)], i);
}
// Reserving buffer for the message
const message_str = "Arbitrary data to hash";
const message_ab = textEncoder.encode(message_str);
const message_arr = reserve(offset, message_ab.length);
for (let i = 0; i < message_ab.length; i++) {
message_arr.set([message_ab.at(i)], i);
}
console.log(`message - ${message_arr}`);
// Reserving buffer for the key
const key = reserve(offset, hydro.secretbox_KEYBYTES);
hydro_secretbox_keygen(key.byteOffset);
console.log(`generated key - ${key.toString("hex")}`);
// Reserving buffer for the cipher text
const cipherTextLength = hydro.secretbox_HEADERBYTES + message_arr.length;
const ciphertext = reserve(offset, cipherTextLength);
// Enciphering single message (thus use of msg_id 0n -- 'n' as libhydrogen expects i64)
hydro_secretbox_encrypt(
ciphertext.byteOffset,
message_arr.byteOffset,
message_arr.byteLength,
0n,
context_arr.byteOffset,
key.byteOffset,
);
// Reserving buffer for the decrypted plain text
const decryptedPlaintextLength = ciphertext.byteLength - hydro.secretbox_HEADERBYTES;
const decryptedPlaintext = reserve(offset, decryptedPlaintextLength);
// Deciphering single message (thus use of msg_id 0n -- 'n' as libhydrogen expects i64)
const res = hydro_secretbox_decrypt(
decryptedPlaintext.byteOffset,
ciphertext.byteOffset,
ciphertext.byteLength,
0n,
context_arr.byteOffset,
key.byteOffset,
);
if (res === 0) {
// As secretbox is an authenticated encryption (AEAD) algorithm
// we check that the ciphertext was authentic
console.log("cipherText not forged");
// Decoding Uint8 encoded string
const textDecoder = new TextDecoder();
console.log(`decryptedPlaintext - ${textDecoder.decode(decryptedPlaintext)}`);
}
message_arr.fill(0);
key.fill(0);
ciphertext.fill(0);
decryptedPlaintext.fill(0);
}
//
// Symmetric Encryption using a Key Generated
// via Asymmetric key exchange
//
function symmetric_encryption_via_asymmetric_key_exchange() {
console.log("\n=== symmetric_encryption_via_asymmetric_key_exchange ===\n");
const { hydro_kx_keygen, hydro_kx_kk_1, hydro_kx_kk_2, hydro_kx_kk_3 } = instance.exports;
const textEncoder = new TextEncoder();
//
// Reserve space in the buffer for the keypair exchange
//
// Both Alice and Bob need a keypair
//
// Both Alice and bob need a pair of session keys
// tx to encrpyt
// rx to decrypt
//
// Alice initiates the key exchange, so she also needs a kx state
// buffer
//
const offset = { value: 0 };
const alice = {
static: {
pk: reserve(offset, hydro.kx_PUBLICKEYBYTES),
sk: reserve(offset, hydro.kx_SECRETKEYBYTES),
},
session: {
rx: reserve(offset, hydro.kx_SESSIONKEYBYTES),
tx: reserve(offset, hydro.kx_SESSIONKEYBYTES),
},
return {
context,
input,
signature: Buffer.from(signature).toString("hex")
};
const bob = {
static: {
pk: reserve(offset, hydro.kx_PUBLICKEYBYTES),
sk: reserve(offset, hydro.kx_SECRETKEYBYTES),
},
session: {
rx: reserve(offset, hydro.kx_SESSIONKEYBYTES),
tx: reserve(offset, hydro.kx_SESSIONKEYBYTES),
},
};
const keysOffset = offset.value;
alice.state = reserve(offset, hydro.kx_SESSIONKEYBYTES);
// We need two "packets" for the messages exchanged between
// Alice and Bob during the key exchange
const packets = {
1: reserve(offset, hydro.kx_KK_PACKET1BYTES),
2: reserve(offset, hydro.kx_KK_PACKET2BYTES),
};
console.log("\n=== symmetric_encryption_via_asymmetric_key_exchange ===\n");
//
// Generate the static keys
//
console.log("------------ALICEKEYGEN------------");
hydro_kx_keygen(alice.static.pk.byteOffset);
console.log("---------------ALICE---------------");
console.log(alice);
console.log("-------------BOBKEYGEN-------------");
hydro_kx_keygen(bob.static.pk.byteOffset);
console.log("----------------BOB----------------");
console.log(bob);
//
// Key exchange
//
// Performing kk_1 (Generating alice's ephemeral keypair and packet 1)
console.log("-----------hydro_kx_kk_1-----------");
hydro_kx_kk_1(
alice.state.byteOffset,
packets[1].byteOffset,
bob.static.pk.byteOffset,
alice.static.pk.byteOffset,
);
console.log("---------------ALICE---------------");
console.dir(alice, { maxArrayLength: null });
console.log("--------------packets--------------");
console.log(packets);
// Performing kk_2 (Generating bob's response packet 2 and his copy of session keys)
console.log("-----------hydro_kx_kk_2-----------");
hydro_kx_kk_2(
bob.session.rx.byteOffset,
packets[2].byteOffset,
packets[1].byteOffset,
alice.static.pk.byteOffset,
bob.static.pk.byteOffset,
);
console.log("----------------BOB----------------");
console.dir(bob, { maxArrayLength: null });
console.log("--------------packets--------------");
console.log(packets);
// Performing kk_3 (Generating Alice's copy of session keys)
console.log("-----------hydro_kx_kk_3-----------");
hydro_kx_kk_3(
alice.state.byteOffset,
alice.session.rx.byteOffset,
packets[2].byteOffset,
alice.static.pk.byteOffset,
);
console.log("---------------ALICE---------------");
console.dir(alice, { maxArrayLength: null });
console.log("-----------KEYS EXCHANGED----------");
// Tidy up the buffer space used in the key exchange
alice.state.fill(0);
packets[1].fill(0);
packets[2].fill(0);
offset.value = keysOffset;
//
// Use the session keys to exchange messages
//
const { hydro_secretbox_encrypt, hydro_secretbox_decrypt } = instance.exports;
const context_str = "Examples";
const context_arr = reserve(offset, hydro.hash_CONTEXTBYTES);
const examples_ab = textEncoder.encode(context_str);
for (let i = 0; i < hydro.hash_CONTEXTBYTES; i++) {
context_arr.set([examples_ab.at(i)], i);
}
const message1_str = "Hello Bob";
const message1_ab = textEncoder.encode(message1_str);
const message1_arr = reserve(offset, message1_ab.length);
for (let i = 0; i < message1_ab.length; i++) {
message1_arr.set([message1_ab.at(i)], i);
}
console.log(`message1_arr - ${message1_arr}`);
const ciphertext1_length = hydro.secretbox_HEADERBYTES + message1_arr.length;
const ciphertext1_arr = reserve(offset, ciphertext1_length);
//
// Alice Encypts the message with her session tx key
//
// Enciphering single message (thus use of msg_id 0n -- 'n' as libhydrogen expects i64)
//
hydro_secretbox_encrypt(
ciphertext1_arr.byteOffset,
message1_arr.byteOffset,
message1_arr.byteLength,
0n,
context_arr.byteOffset,
alice.session.tx.byteOffset,
);
//
// Bob Decrypts the mesaage with his session rx key
//
// Deciphering single message (thus use of msg_id 0n -- 'n' as libhydrogen expects i64)
//
const decryptedPlaintext1Length = ciphertext1_arr.byteLength - hydro.secretbox_HEADERBYTES;
const decryptedPlaintext1 = reserve(offset, decryptedPlaintext1Length);
const res1 = hydro_secretbox_decrypt(
decryptedPlaintext1.byteOffset,
ciphertext1_arr.byteOffset,
ciphertext1_arr.byteLength,
0n,
context_arr.byteOffset,
bob.session.rx.byteOffset,
);
// As secretbox is an authenticated encryption (AEAD) algorithm
// we check that the ciphertext was authentic
if (res1 === 0) {
console.log("ciphertext1_arr not forged");
// Decoding Uint8 encoded string
const textDecoder = new TextDecoder();
console.log(`decryptedPlaintext1 - ${textDecoder.decode(decryptedPlaintext1)}`);
}
//
// Bob sends a reply to Alice
//
const message2_str = "Hello Alice";
const message2_ab = textEncoder.encode(message2_str);
const message2_arr = reserve(offset, message2_ab.length);
for (let i = 0; i < message2_ab.length; i++) {
message2_arr.set([message2_ab.at(i)], i);
}
console.log(`message2_arr - ${message2_arr}`);
const ciphertext2Length = hydro.secretbox_HEADERBYTES + message2_arr.length;
const ciphertext2_arr = reserve(offset, ciphertext2Length);
//
// Bob encrypts the message with his session tx key
//
hydro_secretbox_encrypt(
ciphertext2_arr.byteOffset,
message2_arr.byteOffset,
message2_arr.byteLength,
0n,
context_arr.byteOffset,
bob.session.tx.byteOffset,
);
//
// Alice decrypts the message with her session rx key
//
const decryptedPlaintext2Length = ciphertext2_arr.byteLength - hydro.secretbox_HEADERBYTES;
const decryptedPlaintext2_arr = reserve(offset, decryptedPlaintext2Length);
const res2 = hydro_secretbox_decrypt(
decryptedPlaintext2_arr.byteOffset,
ciphertext2_arr.byteOffset,
ciphertext2_arr.byteLength,
0n,
context_arr.byteOffset,
alice.session.rx.byteOffset,
);
// As secretbox is an authenticated encryption (AEAD) algorithm
// we check that the ciphertext was authentic
if (res2 === 0) {
console.log("ciphertext2 not forged");
const textDecoder = new TextDecoder();
// Decoding Uint8 encoded string
console.log(`decryptedPlaintext2 - ${textDecoder.decode(decryptedPlaintext2_arr)}`);
}
}
export default LibHydrogenCurve25519Signing;