1import {2 initSync,3 WasmNoiseSession,4} from "./noise-core-wasm/peach_noise_core";5import { PEACH_NOISE_CORE_WASM_BASE64 } from "./noise-core-wasm/peach_noise_core_bytes";67export interface RustNoiseSession {8 encrypt(plaintext: Uint8Array): Uint8Array;9 decrypt(ciphertext: Uint8Array): Uint8Array;10 readonly handshakeHash: Uint8Array;11 rekeyOutgoing(): void;12 rekeyIncoming(): void;13 close(): void;14}1516export interface RustNoiseKeyPair {17 publicKey: Uint8Array;18 secretKey: Uint8Array;19}2021let initialized = false;2223function ensureInitialized(): void {24 if (initialized) return;25 const binary = atob(PEACH_NOISE_CORE_WASM_BASE64);26 const bytes = new Uint8Array(binary.length);27 for (let index = 0; index < binary.length; index += 1) {28 bytes[index] = binary.charCodeAt(index);29 }30 try {31 initSync({ module: bytes });32 initialized = true;33 } finally {34 bytes.fill(0);35 }36}3738function session(native: WasmNoiseSession): RustNoiseSession {39 let closed = false;40 const requireOpen = () => {41 if (closed) throw new Error("Noise session is closed");42 };43 return {44 encrypt(plaintext) {45 requireOpen();46 return native.encrypt(plaintext);47 },48 decrypt(ciphertext) {49 requireOpen();50 return native.decrypt(ciphertext);51 },52 get handshakeHash() {53 requireOpen();54 return native.handshakeHash;55 },56 rekeyOutgoing() {57 requireOpen();58 native.rekeyOutgoing();59 },60 rekeyIncoming() {61 requireOpen();62 native.rekeyIncoming();63 },64 close() {65 if (closed) return;66 closed = true;67 native.free();68 },69 };70}7172async function driveInitiator(73 native: WasmNoiseSession,74 send: (message: Uint8Array) => Promise<void>,75 receive: () => Promise<Uint8Array>,76): Promise<RustNoiseSession> {77 try {78 await send(native.writeHandshake(new Uint8Array(0)));79 native.readHandshake(await receive());80 return session(native);81 } catch (error) {82 native.free();83 throw error;84 }85}8687async function driveResponder(88 native: WasmNoiseSession,89 send: (message: Uint8Array) => Promise<void>,90 receive: () => Promise<Uint8Array>,91): Promise<RustNoiseSession> {92 try {93 native.readHandshake(await receive());94 await send(native.writeHandshake(new Uint8Array(0)));95 return session(native);96 } catch (error) {97 native.free();98 throw error;99 }100}101102export async function rustNoiseNkInitiator(103 responderStaticPublicKey: Uint8Array,104 send: (message: Uint8Array) => Promise<void>,105 receive: () => Promise<Uint8Array>,106): Promise<RustNoiseSession> {107 ensureInitialized();108 const native = WasmNoiseSession.nkInitiator(responderStaticPublicKey);109 return driveInitiator(native, send, receive);110}111112export async function rustNoiseNkResponder(113 ourStaticPrivateKey: Uint8Array,114 ourStaticPublicKey: Uint8Array,115 send: (message: Uint8Array) => Promise<void>,116 receive: () => Promise<Uint8Array>,117): Promise<RustNoiseSession> {118 ensureInitialized();119 const native = WasmNoiseSession.nkResponder(ourStaticPrivateKey, ourStaticPublicKey);120 return driveResponder(native, send, receive);121}122123export async function rustNoiseKkInitiator(124 ourStaticPrivateKey: Uint8Array,125 ourStaticPublicKey: Uint8Array,126 responderStaticPublicKey: Uint8Array,127 send: (message: Uint8Array) => Promise<void>,128 receive: () => Promise<Uint8Array>,129): Promise<RustNoiseSession> {130 ensureInitialized();131 const native = WasmNoiseSession.kkInitiator(132 ourStaticPrivateKey,133 ourStaticPublicKey,134 responderStaticPublicKey,135 );136 return driveInitiator(native, send, receive);137}138139export async function rustNoiseKkResponder(140 ourStaticPrivateKey: Uint8Array,141 ourStaticPublicKey: Uint8Array,142 expectedInitiatorStaticPublicKey: Uint8Array,143 send: (message: Uint8Array) => Promise<void>,144 receive: () => Promise<Uint8Array>,145): Promise<RustNoiseSession> {146 ensureInitialized();147 const native = WasmNoiseSession.kkResponder(148 ourStaticPrivateKey,149 ourStaticPublicKey,150 expectedInitiatorStaticPublicKey,151 );152 return driveResponder(native, send, receive);153}154