Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154// Beacon SDK Crypto — uses libsodium-wrappers-sumo for all primitives// Ed25519 keypair for Beacon identity, crypto_box for encrypted messaging
import _sodium from 'libsodium-wrappers-sumo';
let sodium = null;
async function ensureSodium() { if (sodium) return sodium; await _sodium.ready; sodium = _sodium; return sodium;}
// --- Hex helpers ---
function bytesToHex(bytes) { return Array.from(bytes) .map((b) => b.toString(16).padStart(2, '0')) .join('');}
function hexToBytes(hex) { const bytes = new Uint8Array(hex.length / 2); for (let i = 0; i < bytes.length; i++) { bytes[i] = parseInt(hex.substr(i * 2, 2), 16); } return bytes;}
// --- Beacon keypair (persistent Ed25519, separate from Tezos key) ---
export async function getOrCreateBeaconKeypair() { const s = await ensureSodium();
const stored = await chrome.storage.local.get('beacon_keypair_seed'); let seed; if (stored.beacon_keypair_seed) { seed = hexToBytes(stored.beacon_keypair_seed); } else { seed = s.randombytes_buf(32); await chrome.storage.local.set({ beacon_keypair_seed: bytesToHex(seed), }); }
const kp = s.crypto_sign_seed_keypair(seed); return { publicKey: kp.publicKey, // Uint8Array 32 bytes secretKey: kp.privateKey, // Uint8Array 64 bytes };}
// --- Key conversion: Ed25519 → Curve25519 (X25519) for crypto_box ---
export async function ed25519PublicKeyToCurve25519(edPk) { const s = await ensureSodium(); return s.crypto_sign_ed25519_pk_to_curve25519(edPk);}
export async function ed25519SecretKeyToCurve25519(edSk) { const s = await ensureSodium(); return s.crypto_sign_ed25519_sk_to_curve25519(edSk);}
// --- Sender ID (first 5 bytes of blake2b hash of public key, hex) ---
export async function getSenderId(publicKey) { const s = await ensureSodium(); // publicKey can be Uint8Array or hex string const pkBytes = typeof publicKey === 'string' ? hexToBytes(publicKey) : publicKey; const hash = s.crypto_generichash(5, pkBytes); return bytesToHex(hash);}
// --- Encrypt a Beacon message ---// Returns hex string of (nonce || ciphertext)// recipientPublicKey and senderSecretKey are Ed25519 keys — converted internally
export async function encryptBeaconMessage( message, recipientEdPublicKey, senderEdSecretKey,) { const s = await ensureSodium();
// Convert Ed25519 keys to Curve25519 const recipientX25519PK = await ed25519PublicKeyToCurve25519(recipientEdPublicKey); const senderX25519SK = await ed25519SecretKeyToCurve25519(senderEdSecretKey);
// Generate random nonce (24 bytes for crypto_box) const nonce = s.randombytes_buf(24);
// Encode message as UTF-8 bytes const msgBytes = typeof message === 'string' ? new TextEncoder().encode(message) : message;
// Encrypt const ciphertext = s.crypto_box_easy( msgBytes, nonce, recipientX25519PK, senderX25519SK, );
// Combine nonce + ciphertext and return as hex const combined = new Uint8Array(nonce.length + ciphertext.length); combined.set(nonce, 0); combined.set(ciphertext, nonce.length);
return bytesToHex(combined);}
// --- Decrypt a Beacon message ---// encryptedHex is hex string of (nonce || ciphertext)// senderPublicKey and recipientSecretKey are Ed25519 keys
export async function decryptBeaconMessage( encryptedHex, senderEdPublicKey, recipientEdSecretKey,) { const s = await ensureSodium();
const combined = hexToBytes(encryptedHex);
// Extract nonce (first 24 bytes) and ciphertext const nonce = combined.slice(0, 24); const ciphertext = combined.slice(24);
// Convert Ed25519 keys to Curve25519 const senderX25519PK = await ed25519PublicKeyToCurve25519(senderEdPublicKey); const recipientX25519SK = await ed25519SecretKeyToCurve25519(recipientEdSecretKey);
// Decrypt const decrypted = s.crypto_box_open_easy( ciphertext, nonce, senderX25519PK, recipientX25519SK, );
return new TextDecoder().decode(decrypted);}
export { bytesToHex, hexToBytes };