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 ephemeral?: RustNoiseKeyPair,107): Promise<RustNoiseSession> {108 ensureInitialized();109 const native = ephemeral110 ? WasmNoiseSession.nkInitiatorWithEphemeralForTest(111 responderStaticPublicKey,112 ephemeral.secretKey,113 )114 : WasmNoiseSession.nkInitiator(responderStaticPublicKey);115 return driveInitiator(native, send, receive);116}117118export async function rustNoiseNkResponder(119 ourStaticPrivateKey: Uint8Array,120 ourStaticPublicKey: Uint8Array,121 send: (message: Uint8Array) => Promise<void>,122 receive: () => Promise<Uint8Array>,123 ephemeral?: RustNoiseKeyPair,124): Promise<RustNoiseSession> {125 ensureInitialized();126 const native = ephemeral127 ? WasmNoiseSession.nkResponderWithEphemeralForTest(128 ourStaticPrivateKey,129 ourStaticPublicKey,130 ephemeral.secretKey,131 )132 : WasmNoiseSession.nkResponder(ourStaticPrivateKey, ourStaticPublicKey);133 return driveResponder(native, send, receive);134}135136export async function rustNoiseKkInitiator(137 ourStaticPrivateKey: Uint8Array,138 ourStaticPublicKey: Uint8Array,139 responderStaticPublicKey: Uint8Array,140 send: (message: Uint8Array) => Promise<void>,141 receive: () => Promise<Uint8Array>,142 ephemeral?: RustNoiseKeyPair,143): Promise<RustNoiseSession> {144 ensureInitialized();145 const native = ephemeral146 ? WasmNoiseSession.kkInitiatorWithEphemeralForTest(147 ourStaticPrivateKey,148 ourStaticPublicKey,149 responderStaticPublicKey,150 ephemeral.secretKey,151 )152 : WasmNoiseSession.kkInitiator(153 ourStaticPrivateKey,154 ourStaticPublicKey,155 responderStaticPublicKey,156 );157 return driveInitiator(native, send, receive);158}159160export async function rustNoiseKkResponder(161 ourStaticPrivateKey: Uint8Array,162 ourStaticPublicKey: Uint8Array,163 expectedInitiatorStaticPublicKey: Uint8Array,164 send: (message: Uint8Array) => Promise<void>,165 receive: () => Promise<Uint8Array>,166 ephemeral?: RustNoiseKeyPair,167): Promise<RustNoiseSession> {168 ensureInitialized();169 const native = ephemeral170 ? WasmNoiseSession.kkResponderWithEphemeralForTest(171 ourStaticPrivateKey,172 ourStaticPublicKey,173 expectedInitiatorStaticPublicKey,174 ephemeral.secretKey,175 )176 : WasmNoiseSession.kkResponder(177 ourStaticPrivateKey,178 ourStaticPublicKey,179 expectedInitiatorStaticPublicKey,180 );181 return driveResponder(native, send, receive);182}183