@gorbchain-xyz/chaindecode
Version:
GorbchainSDK V1.3+ - Complete Solana development toolkit with advanced cryptography, messaging, and collaboration features. Build secure applications with blockchain, DeFi, and end-to-end encryption.
269 lines (268 loc) • 9 kB
JavaScript
/**
* Utility functions for cryptographic operations
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
import { bytesToBase58 as encodeBase58, base58ToBytes as decodeBase58 } from '../utils/base58.js';
import { Keypair, PublicKey } from '@solana/web3.js';
import nacl from 'tweetnacl';
import { Buffer } from 'buffer';
// Constants
export const ENCRYPTION_ALGORITHM = 'aes-256-gcm';
export const KEY_SIZE = 32; // 256 bits
export const IV_SIZE = 16; // 128 bits
export const SALT_SIZE = 32; // 256 bits
export const AUTH_TAG_SIZE = 16; // 128 bits
export const KEY_DERIVATION_ITERATIONS = 100000;
/**
* Generate cryptographically secure random bytes
*/
export function generateRandomBytes(length) {
return new Uint8Array(randomBytes(length));
}
/**
* Derive a key from password/secret using PBKDF2
*/
export function deriveKey(secret, salt, iterations = KEY_DERIVATION_ITERATIONS) {
// Simple PBKDF2 implementation
let result = Buffer.concat([secret, salt]);
for (let i = 0; i < iterations; i++) {
const hash = createHash('sha256'); // Create new hash object each iteration
result = Buffer.from(hash.update(result).digest());
}
return new Uint8Array(result.slice(0, KEY_SIZE));
}
/**
* Generate a key pair for encryption (compatible with Solana format)
*/
export function generateKeyPair() {
// Use Solana keypair for consistency
const solanaKeypair = Keypair.generate();
return {
publicKey: solanaKeypair.publicKey.toBytes(),
privateKey: solanaKeypair.secretKey
};
}
/**
* Convert ed25519 public key to curve25519 for encryption
*/
export function ed25519ToCurve25519PublicKey(ed25519PublicKey) {
// This is a simplified conversion - in production use proper libraries
const hash = createHash('sha256').update(ed25519PublicKey).digest();
return new Uint8Array(hash.slice(0, 32));
}
/**
* Convert ed25519 private key to curve25519 for encryption
*/
export function ed25519ToCurve25519PrivateKey(ed25519PrivateKey) {
// Extract the actual private key part (first 32 bytes)
return new Uint8Array(ed25519PrivateKey.slice(0, 32));
}
/**
* Perform symmetric key exchange
* This ensures both sides get the same shared secret regardless of call order
*/
export function performKeyExchange(privateKey, publicKey) {
// Validate inputs
if (!privateKey || !publicKey) {
throw new Error('Invalid keys for key exchange');
}
try {
// Extract seed from private key if it's a full ed25519 key (64 bytes)
const privSeed = privateKey.length === 64 ? privateKey.slice(0, 32) : privateKey;
// Simple but effective: XOR the keys and hash the result
// This is symmetric and deterministic
const combined = new Uint8Array(32);
for (let i = 0; i < 32; i++) {
combined[i] = privSeed[i] ^ publicKey[i];
}
// Hash the result for additional security
const hash = createHash('sha256');
hash.update(combined);
return new Uint8Array(hash.digest());
}
catch (error) {
throw new Error(`Key exchange failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Encrypt data using AES-256-GCM
*/
export function encryptAES(data, key, iv) {
const initVector = iv || generateRandomBytes(IV_SIZE);
const cipher = createCipheriv(ENCRYPTION_ALGORITHM, key, initVector);
const encrypted = Buffer.concat([
cipher.update(data),
cipher.final()
]);
const authTag = cipher.getAuthTag();
return {
encrypted: new Uint8Array(encrypted),
iv: initVector,
authTag: new Uint8Array(authTag)
};
}
/**
* Decrypt data using AES-256-GCM
*/
export function decryptAES(encrypted, key, iv, authTag) {
const decipher = createDecipheriv(ENCRYPTION_ALGORITHM, key, iv);
decipher.setAuthTag(authTag);
try {
const decrypted = Buffer.concat([
decipher.update(encrypted),
decipher.final()
]);
return new Uint8Array(decrypted);
}
catch (error) {
throw new Error('Decryption failed: Invalid key or corrupted data');
}
}
/**
* Sign data using ed25519
*/
export function signData(data, privateKey) {
// Convert string data to bytes if needed
const dataBytes = typeof data === 'string' ? stringToBytes(data) : data;
const privateKeyBytes = typeof privateKey === 'string'
? decodeBase58(privateKey)
: privateKey;
// Ensure we have a full keypair and it's a Uint8Array
let keypair;
if (privateKeyBytes.length === 64) {
keypair = new Uint8Array(privateKeyBytes);
}
else {
const solanaKeypair = Keypair.fromSeed(new Uint8Array(privateKeyBytes.slice(0, 32)));
keypair = new Uint8Array(solanaKeypair.secretKey);
}
return nacl.sign.detached(new Uint8Array(dataBytes), keypair);
}
/**
* Verify signature using ed25519
*/
export function verifySignature(data, signature, publicKey) {
// Convert string inputs to bytes
const dataBytes = typeof data === 'string' ? stringToBytes(data) : data;
const signatureBytes = typeof signature === 'string' ? decodeBase58(signature) : signature;
const publicKeyBytes = typeof publicKey === 'string' ? decodeBase58(publicKey) : publicKey;
// Ensure all parameters are Uint8Arrays for TweetNaCl compatibility
return nacl.sign.detached.verify(new Uint8Array(dataBytes), new Uint8Array(signatureBytes), new Uint8Array(publicKeyBytes));
}
/**
* Compress data using zlib
*/
export function compressData(data) {
return __awaiter(this, void 0, void 0, function* () {
const zlib = yield import('zlib');
return new Promise((resolve, reject) => {
zlib.deflate(data, (err, compressed) => {
if (err)
reject(err);
else
resolve(new Uint8Array(compressed));
});
});
});
}
/**
* Decompress data using zlib
*/
export function decompressData(compressed) {
return __awaiter(this, void 0, void 0, function* () {
const zlib = yield import('zlib');
return new Promise((resolve, reject) => {
zlib.inflate(compressed, (err, decompressed) => {
if (err)
reject(err);
else
resolve(new Uint8Array(decompressed));
});
});
});
}
/**
* Generate a deterministic ID from multiple inputs
*/
export function generateId(...inputs) {
const hash = createHash('sha256');
for (const input of inputs) {
const data = typeof input === 'string'
? Buffer.from(input, 'utf-8')
: input;
hash.update(data);
}
return encodeBase58(hash.digest());
}
/**
* Combine multiple buffers
*/
export function combineBuffers(...buffers) {
const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);
const result = new Uint8Array(totalLength);
let offset = 0;
for (const buffer of buffers) {
result.set(buffer, offset);
offset += buffer.length;
}
return result;
}
/**
* Split a buffer at specific positions
*/
export function splitBuffer(buffer, ...lengths) {
const result = [];
let offset = 0;
for (const length of lengths) {
result.push(buffer.slice(offset, offset + length));
offset += length;
}
// Always add remaining data (even if empty)
result.push(buffer.slice(offset));
return result;
}
/**
* Convert string to Uint8Array
*/
export function stringToBytes(str) {
return new Uint8Array(Buffer.from(str, 'utf-8'));
}
/**
* Convert Uint8Array to string
*/
export function bytesToString(bytes) {
return Buffer.from(bytes).toString('utf-8');
}
/**
* Validate Solana public key
*/
export function isValidPublicKey(publicKey) {
try {
new PublicKey(publicKey);
return true;
}
catch (_a) {
return false;
}
}
/**
* Get current timestamp in seconds
*/
export function getCurrentTimestamp() {
return Math.floor(Date.now() / 1000);
}
/**
* Check if a timestamp has expired
*/
export function hasExpired(timestamp, ttlSeconds) {
return getCurrentTimestamp() > timestamp + ttlSeconds;
}