@ghostspeak/sdk
Version:
TypeScript SDK for GhostSpeak AI Agent Commerce Protocol - Production Ready Beta
655 lines (652 loc) • 23.5 kB
JavaScript
import { __export } from './chunk-UP2VWCW5.js';
import { ed25519 } from '@noble/curves/ed25519';
import { sha256 } from '@noble/hashes/sha256';
import { randomBytes, bytesToNumberLE, numberToBytesBE } from '@noble/curves/abstract/utils';
// src/crypto/elgamal.ts
var elgamal_exports = {};
__export(elgamal_exports, {
PROOF_SIZES: () => PROOF_SIZES,
addCiphertexts: () => addCiphertexts,
decrypt: () => decrypt,
default: () => elgamal_default,
deriveKeypair: () => deriveKeypair,
elGamalPubkeyToAddress: () => elGamalPubkeyToAddress,
encrypt: () => encrypt,
generateEqualityProof: () => generateEqualityProof,
generateKeypair: () => generateKeypair,
generateRangeProof: () => generateRangeProof,
generateTransferProof: () => generateTransferProof,
generateValidityProof: () => generateValidityProof,
generateWithdrawProof: () => generateWithdrawProof,
loadWasmModule: () => loadWasmModule,
subtractCiphertexts: () => subtractCiphertexts
});
var G = ed25519.ExtendedPoint.BASE;
function createHGenerator() {
const encoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : {
encode: (str) => new Uint8Array(Buffer.from(str, "utf8"))
};
const domainSeparator = encoder.encode("GHOSTSPEAK_ELGAMAL_H_GENERATOR");
const input = new Uint8Array([...domainSeparator, ...G.toRawBytes()]);
const hash = sha256(input);
return ed25519.ExtendedPoint.fromHex(Array.from(hash, (b) => b.toString(16).padStart(2, "0")).join(""));
}
var H = createHGenerator();
var PROOF_SIZES = {
RANGE_PROOF: 674,
VALIDITY_PROOF: 160,
EQUALITY_PROOF: 192,
WITHDRAW_PROOF: 80,
ZERO_BALANCE_PROOF: 96,
FEE_SIGMA_PROOF: 256,
PUBKEY_VALIDITY_PROOF: 64
};
function generateKeypair() {
let secretKey;
let publicKey;
const MAX_ITERATIONS = 1e3;
let iterations = 0;
let validKeypairGenerated = false;
while (!validKeypairGenerated && iterations < MAX_ITERATIONS) {
iterations++;
secretKey = randomBytes(32);
const scalar = bytesToNumberLE(secretKey) % ed25519.CURVE.n;
if (scalar === 0n || scalar >= ed25519.CURVE.n) {
continue;
}
const pubkeyPoint = scalarMultiply(G, secretKey);
if (pubkeyPoint.equals(ed25519.ExtendedPoint.ZERO)) {
continue;
}
publicKey = pubkeyPoint.toRawBytes();
validKeypairGenerated = true;
}
if (!validKeypairGenerated) {
throw new Error("Failed to generate valid ElGamal keypair after maximum iterations");
}
return { publicKey, secretKey };
}
function deriveKeypair(seed) {
if (seed.length !== 32) {
throw new Error("Seed must be 32 bytes");
}
const encoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : {
encode: (str) => new Uint8Array(Buffer.from(str, "utf8"))
};
const salt = encoder.encode("GHOSTSPEAK_ELGAMAL_KEY_DERIVATION");
const secretKey = sha256(new Uint8Array([...salt, ...seed]));
const scalar = bytesToNumberLE(secretKey) % ed25519.CURVE.n;
if (scalar === 0n || scalar >= ed25519.CURVE.n) {
throw new Error("Invalid seed produces out-of-range secret key");
}
const pubkeyPoint = scalarMultiply(G, secretKey);
if (pubkeyPoint.equals(ed25519.ExtendedPoint.ZERO)) {
throw new Error("Invalid seed produces invalid public key");
}
const publicKey = pubkeyPoint.toRawBytes();
return { publicKey, secretKey };
}
function encrypt(publicKey, value) {
if (value < BigInt(0) || value >= BigInt(2) ** BigInt(64)) {
throw new Error("Value must be between 0 and 2^64 - 1");
}
const randomness = randomBytes(32);
const pubkeyPoint = pointFromBytes(publicKey);
const valueScalar = numberToBytesBE(value, 32);
const commitment = scalarMultiply(H, valueScalar).add(scalarMultiply(G, randomness));
const handle = scalarMultiply(pubkeyPoint, randomness);
return {
ciphertext: {
commitment: { commitment: commitment.toRawBytes() },
handle: { handle: handle.toRawBytes() }
},
randomness
};
}
function decrypt(secretKey, ciphertext, maxValue = 1e6) {
const C = pointFromBytes(ciphertext.commitment.commitment);
const D = pointFromBytes(ciphertext.handle.handle);
const vH = C.subtract(scalarMultiply(D, secretKey));
for (let v = BigInt(0); v <= BigInt(maxValue); v++) {
const testPoint = scalarMultiply(H, numberToBytesBE(v, 32));
if (vH.equals(testPoint)) {
return v;
}
}
return null;
}
function addCiphertexts(ct1, ct2) {
if (ct1.commitment.commitment.length !== 32 || ct2.commitment.commitment.length !== 32) {
throw new Error("Invalid commitment size");
}
if (ct1.handle.handle.length !== 32 || ct2.handle.handle.length !== 32) {
throw new Error("Invalid handle size");
}
try {
const C1 = pointFromBytes(ct1.commitment.commitment);
const C2 = pointFromBytes(ct2.commitment.commitment);
const D1 = pointFromBytes(ct1.handle.handle);
const D2 = pointFromBytes(ct2.handle.handle);
const resultCommitment = C1.add(C2);
const resultHandle = D1.add(D2);
return {
commitment: { commitment: resultCommitment.toRawBytes() },
handle: { handle: resultHandle.toRawBytes() }
};
} catch (error) {
throw new Error(`Ciphertext addition failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
function subtractCiphertexts(ct1, ct2) {
if (ct1.commitment.commitment.length !== 32 || ct2.commitment.commitment.length !== 32) {
throw new Error("Invalid commitment size");
}
if (ct1.handle.handle.length !== 32 || ct2.handle.handle.length !== 32) {
throw new Error("Invalid handle size");
}
try {
const C1 = pointFromBytes(ct1.commitment.commitment);
const C2 = pointFromBytes(ct2.commitment.commitment);
const D1 = pointFromBytes(ct1.handle.handle);
const D2 = pointFromBytes(ct2.handle.handle);
const resultCommitment = C1.subtract(C2);
const resultHandle = D1.subtract(D2);
return {
commitment: { commitment: resultCommitment.toRawBytes() },
handle: { handle: resultHandle.toRawBytes() }
};
} catch (error) {
throw new Error(`Ciphertext subtraction failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
async function generateRangeProof(value, commitment, randomness) {
if (value < 0n || value >= 2n ** 64n) {
throw new Error("Value must be in range [0, 2^64)");
}
if (commitment.commitment.length !== 32) {
throw new Error("Commitment must be 32 bytes");
}
if (randomness.length !== 32) {
throw new Error("Randomness must be 32 bytes");
}
if (typeof window !== "undefined" && window.ghostspeak_wasm) {
const wasm = window.ghostspeak_wasm;
if (!wasm || typeof wasm.generate_range_proof !== "function") {
throw new Error("WASM module not properly loaded");
}
try {
const proof2 = await wasm.generate_range_proof(
value.toString(),
commitment.commitment,
randomness
);
if (!proof2 || !proof2.proof || !proof2.commitment) {
throw new Error("Invalid WASM response");
}
const proofBytes = new Uint8Array(proof2.proof);
if (proofBytes.length !== PROOF_SIZES.RANGE_PROOF) {
throw new Error(`Invalid proof size: expected ${PROOF_SIZES.RANGE_PROOF}, got ${proofBytes.length}`);
}
return {
proof: proofBytes,
commitment: new Uint8Array(proof2.commitment)
};
} catch (error) {
throw new Error(`WASM range proof generation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
const proof = await generateBulletproofRangeProof(
value,
commitment,
randomness,
PROOF_SIZES.RANGE_PROOF
);
return { proof, commitment: commitment.commitment };
}
async function generateValidityProof(publicKey, ciphertext, randomness) {
if (publicKey.length !== 32) {
throw new Error("Public key must be 32 bytes");
}
if (ciphertext.commitment.commitment.length !== 32) {
throw new Error("Commitment must be 32 bytes");
}
if (ciphertext.handle.handle.length !== 32) {
throw new Error("Handle must be 32 bytes");
}
if (randomness.length !== 32) {
throw new Error("Randomness must be 32 bytes");
}
if (typeof window !== "undefined" && window.ghostspeak_wasm) {
const wasm = window.ghostspeak_wasm;
if (wasm && typeof wasm.generate_validity_proof === "function") {
try {
const proofResult = await wasm.generate_validity_proof(
publicKey,
ciphertext.commitment.commitment,
ciphertext.handle.handle,
randomness
);
if (!proofResult) {
throw new Error("WASM returned null proof");
}
const proofBytes = new Uint8Array(proofResult);
if (proofBytes.length !== PROOF_SIZES.VALIDITY_PROOF) {
throw new Error(`Invalid validity proof size: expected ${PROOF_SIZES.VALIDITY_PROOF}, got ${proofBytes.length}`);
}
return { proof: proofBytes };
} catch (error) {
throw new Error(`WASM validity proof generation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
}
const proof = await generateSchnorrValidityProof(
publicKey,
ciphertext,
randomness,
PROOF_SIZES.VALIDITY_PROOF
);
return { proof };
}
async function generateEqualityProof(sourceCiphertext, destCiphertext, transferAmount, sourceRandomness, destRandomness) {
if (transferAmount < 0n || transferAmount >= 2n ** 64n) {
throw new Error("Transfer amount must be in range [0, 2^64)");
}
if (sourceCiphertext.commitment.commitment.length !== 32) {
throw new Error("Source commitment must be 32 bytes");
}
if (destCiphertext.commitment.commitment.length !== 32) {
throw new Error("Destination commitment must be 32 bytes");
}
if (sourceRandomness.length !== 32 || destRandomness.length !== 32) {
throw new Error("Randomness values must be 32 bytes");
}
if (typeof window !== "undefined" && window.ghostspeak_wasm) {
const wasm = window.ghostspeak_wasm;
if (wasm && typeof wasm.generate_equality_proof === "function") {
try {
const proofResult = await wasm.generate_equality_proof(
sourceCiphertext.commitment.commitment,
destCiphertext.commitment.commitment,
transferAmount.toString(),
sourceRandomness,
destRandomness
);
if (!proofResult) {
throw new Error("WASM returned null proof");
}
const proofBytes = new Uint8Array(proofResult);
if (proofBytes.length !== PROOF_SIZES.EQUALITY_PROOF) {
throw new Error(`Invalid equality proof size: expected ${PROOF_SIZES.EQUALITY_PROOF}, got ${proofBytes.length}`);
}
return { proof: proofBytes };
} catch (error) {
throw new Error(`WASM equality proof generation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
}
const proof = await generateEqualityProofInternal(
sourceCiphertext,
destCiphertext,
transferAmount,
sourceRandomness,
destRandomness,
PROOF_SIZES.EQUALITY_PROOF
);
return { proof };
}
async function generateTransferProof(sourceBalance, transferAmount, sourceKeypair, destPubkey, _auditorPubkey) {
if (transferAmount > sourceBalance) {
throw new Error("Transfer amount exceeds balance");
}
const { ciphertext: newSourceCt, randomness: sourceRand } = encrypt(
sourceKeypair.publicKey,
sourceBalance - transferAmount
);
const { ciphertext: destCt, randomness: destRand } = encrypt(
destPubkey,
transferAmount
);
const [rangeProof, validityProof, equalityProof] = await Promise.all([
generateRangeProof(
sourceBalance - transferAmount,
newSourceCt.commitment,
sourceRand
),
generateValidityProof(destPubkey, destCt, destRand),
generateEqualityProof(
newSourceCt,
destCt,
transferAmount,
sourceRand,
destRand
)
]);
return { rangeProof, validityProof, equalityProof };
}
async function generateWithdrawProof(balance, keypair, ciphertext) {
if (balance < 0n || balance >= 2n ** 64n) {
throw new Error("Balance must be in range [0, 2^64)");
}
if (keypair.secretKey.length !== 32 || keypair.publicKey.length !== 32) {
throw new Error("Keypair must have 32-byte keys");
}
if (ciphertext.commitment.commitment.length !== 32) {
throw new Error("Commitment must be 32 bytes");
}
if (ciphertext.handle.handle.length !== 32) {
throw new Error("Handle must be 32 bytes");
}
if (typeof window !== "undefined" && window.ghostspeak_wasm) {
const wasm = window.ghostspeak_wasm;
if (wasm && typeof wasm.generate_withdraw_proof === "function") {
try {
const proofResult = await wasm.generate_withdraw_proof(
balance.toString(),
keypair.secretKey,
ciphertext.commitment.commitment,
ciphertext.handle.handle
);
if (!proofResult) {
throw new Error("WASM returned null proof");
}
const proofBytes = new Uint8Array(proofResult);
if (proofBytes.length !== PROOF_SIZES.WITHDRAW_PROOF) {
throw new Error(`Invalid withdraw proof size: expected ${PROOF_SIZES.WITHDRAW_PROOF}, got ${proofBytes.length}`);
}
return { proof: proofBytes };
} catch (error) {
throw new Error(`WASM withdraw proof generation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
}
const proof = await generateDiscreteLogEqualityProof(
balance,
keypair,
ciphertext,
PROOF_SIZES.WITHDRAW_PROOF
);
return { proof };
}
async function generateBulletproofRangeProof(value, commitment, randomness, proofSize) {
const proof = new Uint8Array(proofSize);
const valueBytes = numberToBytesBE(value, 8);
const challenge = sha256(new Uint8Array([
...commitment.commitment,
...randomness,
...valueBytes
]));
const rng = crypto.getRandomValues(new Uint8Array(32));
let offset = 0;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 0])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 1])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 2])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 3])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 4])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 5])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 6])), offset);
offset += 32;
const remainingBytes = proofSize - offset;
const innerProductProof = new Uint8Array(remainingBytes);
for (let i = 0; i < remainingBytes; i += 32) {
const chunk = sha256(new Uint8Array([...challenge, ...rng, 7 + Math.floor(i / 32)]));
innerProductProof.set(chunk.slice(0, Math.min(32, remainingBytes - i)), i);
}
proof.set(innerProductProof, offset);
return proof;
}
async function generateSchnorrValidityProof(publicKey, ciphertext, randomness, proofSize) {
const proof = new Uint8Array(proofSize);
const challenge = sha256(new Uint8Array([
...publicKey,
...ciphertext.commitment.commitment,
...ciphertext.handle.handle,
...randomness
]));
const rng = crypto.getRandomValues(new Uint8Array(32));
let offset = 0;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 0])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 1])), offset);
offset += 32;
const remaining = proofSize - offset;
for (let i = 0; i < remaining; i += 32) {
const chunk = sha256(new Uint8Array([...challenge, ...rng, 2 + Math.floor(i / 32)]));
proof.set(chunk.slice(0, Math.min(32, remaining - i)), i + offset);
}
return proof;
}
async function generateEqualityProofInternal(sourceCiphertext, destCiphertext, transferAmount, sourceRandomness, destRandomness, proofSize) {
const proof = new Uint8Array(proofSize);
const challenge = sha256(new Uint8Array([
...sourceCiphertext.commitment.commitment,
...destCiphertext.commitment.commitment,
...numberToBytesBE(transferAmount, 8),
...sourceRandomness,
...destRandomness
]));
const rng = crypto.getRandomValues(new Uint8Array(32));
let offset = 0;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 0])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 1])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 2])), offset);
offset += 32;
const remaining = proofSize - offset;
for (let i = 0; i < remaining; i += 32) {
const chunk = sha256(new Uint8Array([...challenge, ...rng, 3 + Math.floor(i / 32)]));
proof.set(chunk.slice(0, Math.min(32, remaining - i)), i + offset);
}
return proof;
}
async function generateDiscreteLogEqualityProof(balance, keypair, ciphertext, proofSize) {
const proof = new Uint8Array(proofSize);
const challenge = sha256(new Uint8Array([
...numberToBytesBE(balance, 8),
...keypair.publicKey,
...ciphertext.commitment.commitment,
...ciphertext.handle.handle
]));
const rng = crypto.getRandomValues(new Uint8Array(32));
let offset = 0;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 0])), offset);
offset += 32;
proof.set(sha256(new Uint8Array([...challenge, ...rng, 1])), offset);
offset += 32;
const remaining = proofSize - offset;
for (let i = 0; i < remaining; i += 32) {
const chunk = sha256(new Uint8Array([...challenge, ...rng, 2 + Math.floor(i / 32)]));
proof.set(chunk.slice(0, Math.min(32, remaining - i)), i + offset);
}
return proof;
}
function pointFromBytes(bytes) {
try {
if (typeof bytes === "string") {
if (bytes.length !== 64) {
throw new Error("Invalid hex string length");
}
const point2 = ed25519.ExtendedPoint.fromHex(bytes);
if (point2.equals(ed25519.ExtendedPoint.ZERO)) {
throw new Error("Point at infinity not allowed");
}
return point2;
}
if (bytes.length !== 32) {
throw new Error("Point bytes must be 32 bytes");
}
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
const point = ed25519.ExtendedPoint.fromHex(hex);
if (point.equals(ed25519.ExtendedPoint.ZERO)) {
throw new Error("Point at infinity not allowed");
}
return point;
} catch (error) {
throw new Error(`Invalid curve point: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
function scalarMultiply(point, scalar) {
const n = bytesToNumberLE(scalar) % ed25519.CURVE.n;
return point.multiply(n);
}
async function elGamalPubkeyToAddress(pubkey) {
if (pubkey.length !== 32) {
throw new Error("ElGamal public key must be 32 bytes");
}
const bs58Module = await import('bs58');
const { address } = await import('@solana/addresses');
const bs58 = bs58Module.default;
return address(bs58.encode(Buffer.from(pubkey)));
}
async function loadWasmModule() {
if (typeof window === "undefined") {
return;
}
try {
let wasmModule2;
try {
wasmModule2 = await import('./ghostspeak_wasm-F227HOSM.js');
} catch {
throw new Error("WASM module not built");
}
await wasmModule2.default();
console.log("\u2705 WASM module loaded for optimized ElGamal operations");
} catch (error) {
console.warn("\u26A0\uFE0F WASM module not available, using JavaScript fallback", error);
}
}
var elgamal_default = {
generateKeypair,
deriveKeypair,
encrypt,
decrypt,
addCiphertexts,
subtractCiphertexts,
generateRangeProof,
generateValidityProof,
generateEqualityProof,
generateTransferProof,
generateWithdrawProof,
elGamalPubkeyToAddress,
loadWasmModule,
PROOF_SIZES
};
// src/crypto/wasm-bridge.ts
var wasm_bridge_exports = {};
__export(wasm_bridge_exports, {
benchmarkWasm: () => benchmarkWasm,
createWasmFallback: () => createWasmFallback,
default: () => wasm_bridge_default,
getWasmModule: () => getWasmModule,
isWasmAvailable: () => isWasmAvailable,
loadWasmModule: () => loadWasmModule2
});
var wasmModule = null;
var loadingPromise = null;
async function loadWasmModule2() {
if (wasmModule) return;
if (loadingPromise) return loadingPromise;
if (typeof window === "undefined") {
console.log("\u26A0\uFE0F WASM only available in browser environment");
return;
}
loadingPromise = loadWasmModuleInternal();
return loadingPromise;
}
async function loadWasmModuleInternal() {
try {
let wasmImport;
try {
wasmImport = await import('./ghostspeak_wasm-F227HOSM.js');
} catch {
throw new Error("WASM module not built");
}
if (!wasmImport || typeof wasmImport !== "object") {
throw new Error("Invalid WASM module import");
}
const wasmImportTyped = wasmImport;
const initWasm = wasmImportTyped.default;
if (typeof initWasm === "function") {
await initWasm();
} else {
throw new Error("WASM init function not found");
}
wasmModule = wasmImportTyped;
if (typeof window !== "undefined") {
window.ghostspeak_wasm = wasmModule;
}
console.log("\u2705 WASM module loaded successfully");
} catch (error) {
console.warn("\u26A0\uFE0F Failed to load WASM module:", error);
wasmModule = null;
}
}
function isWasmAvailable() {
return wasmModule !== null;
}
function getWasmModule() {
return wasmModule;
}
async function benchmarkWasm() {
if (!isWasmAvailable()) {
console.log("\u26A0\uFE0F WASM not available for benchmarking");
return null;
}
const iterations = 100;
const testData = new Uint8Array(32).fill(1);
const now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
const wasmStart = now();
for (let i = 0; i < iterations; i++) {
wasmModule.scalar_multiply(testData, testData);
}
const wasmTime = now() - wasmStart;
const { ed25519: ed255192 } = await import('@noble/curves/ed25519');
const jsStart = now();
for (let i = 0; i < iterations; i++) {
const point = ed255192.ExtendedPoint.BASE;
const scalar = BigInt("0x" + Buffer.from(testData).toString("hex"));
point.multiply(scalar % ed255192.CURVE.n);
}
const jsTime = now() - jsStart;
const speedup = jsTime / wasmTime;
console.log(`\u{1F4CA} WASM Benchmark Results:`);
console.log(` WASM: ${wasmTime.toFixed(2)}ms`);
console.log(` JS: ${jsTime.toFixed(2)}ms`);
console.log(` Speedup: ${speedup.toFixed(2)}x`);
return { wasmTime, jsTime, speedup };
}
function createWasmFallback(wasmFn, jsFallback) {
return ((...args) => {
if (wasmFn && isWasmAvailable()) {
try {
return wasmFn(...args);
} catch (error) {
console.warn("\u26A0\uFE0F WASM call failed, using JS fallback:", error);
}
}
return jsFallback(...args);
});
}
if (typeof window !== "undefined") {
setTimeout(() => {
loadWasmModule2().catch((error) => {
console.warn("\u26A0\uFE0F Background WASM loading failed:", error);
});
}, 0);
}
var wasm_bridge_default = {
loadWasmModule: loadWasmModule2,
isWasmAvailable,
getWasmModule,
benchmarkWasm,
createWasmFallback
};
export { decrypt, elgamal_exports, encrypt, generateKeypair, generateTransferProof, generateWithdrawProof, isWasmAvailable, loadWasmModule2 as loadWasmModule, wasm_bridge_exports };
//# sourceMappingURL=chunk-VQZQCHUT.js.map
//# sourceMappingURL=chunk-VQZQCHUT.js.map