Files
2026-03-07 14:15:48 +03:00

169 lines
6.3 KiB
TypeScript

import { keyPairFromSeed, keyPairFromSecretKey, sign, signVerify, KeyPair, getSecureRandomBytes } from '@ton/crypto';
import nacl from 'tweetnacl';
const ed2curve = require('ed2curve');
import { client, getKeypair } from '../toolchain';
import { Content } from '../../build/Gift/Gift_Gift';
import { Address } from '@ton/core';
import { WalletContractV4 } from '@ton/ton';
/**
* Converts a bigint (uint256) to Buffer (32 bytes, big-endian).
* @param bigIntValue The bigint value to convert.
* @param byteLength The byte length (default 32 for uint256).
* @returns Buffer The converted byte buffer.
*/
function bigIntToBuffer(bigIntValue: bigint, byteLength: number = 32): Buffer {
const buffer = Buffer.alloc(byteLength);
for (let i = 0; i < byteLength; i++) {
buffer[byteLength - 1 - i] = Number((bigIntValue >> BigInt(i * 8)) & 0xffn);
}
return buffer;
}
/**
* Get the public key of the recipient wallet.
* @param address The recipient's TON address.
* @returns Promise<Buffer> The recipient's public key as Buffer.
*/
export async function getRecipientPublicKey(address: Address): Promise<Buffer> {
console.log(`Fetching public key for: ${address.toString()}`);
return client.callGetMethod(address, 'get_public_key')
.then((result) => {
return bigIntToBuffer(result.stack.readBigNumber());
})
.catch((error) => {
console.error('Error fetching recipient public key:', error);
throw error;
});
}
/**
* Encrypt a Content message using sender's private key and recipient's public key.
* @param content The Content to encrypt.
* @param senderSecretKey The sender's secret key.
* @param recipientPublicKey The recipient's public key.
* @returns Promise<Uint8Array> The encrypted message data (nonce + encrypted).
*/
export async function encryptMessage(
content: Content,
senderSecretKey: Buffer,
recipientPublicKey: Buffer,
): Promise<Uint8Array> {
// Serialize Content to JSON string
const contentString = JSON.stringify(content);
const contentBuffer = new Uint8Array(Buffer.from(contentString, 'utf-8'));
// Convert Ed25519 keys to Curve25519
const senderSecretCurve = ed2curve.convertSecretKey(senderSecretKey);
const recipientPublicCurve = ed2curve.convertPublicKey(recipientPublicKey);
if (!senderSecretCurve || !recipientPublicCurve) {
throw new Error('Invalid key conversion');
}
// Generate a random nonce
const nonceBuffer = await getSecureRandomBytes(24);
const nonce = new Uint8Array(nonceBuffer);
// Encrypt using NaCl box
const encrypted = nacl.box(contentBuffer, nonce, recipientPublicCurve, senderSecretCurve);
// Return nonce + encrypted
const combined = new Uint8Array(nonce.length + encrypted.length);
combined.set(nonce, 0);
combined.set(encrypted, nonce.length);
return combined;
}
/**
* Decrypt an encrypted message using recipient's private key and sender's public key.
* @param encryptedData The encrypted data (nonce + encrypted).
* @param recipientSecretKey The recipient's secret key.
* @param senderPublicKey The sender's public key.
* @returns Promise<Content> The decrypted Content.
*/
export async function decryptMessage(
encryptedData: Uint8Array,
recipientSecretKey: Buffer,
senderPublicKey: Buffer,
): Promise<Content> {
// Extract nonce (first 24 bytes)
const nonce = encryptedData.slice(0, 24);
const encrypted = encryptedData.slice(24);
// Convert Ed25519 keys to Curve25519
const recipientSecretCurve = ed2curve.convertSecretKey(recipientSecretKey);
const senderPublicCurve = ed2curve.convertPublicKey(senderPublicKey);
if (!recipientSecretCurve || !senderPublicCurve) {
throw new Error('Invalid key conversion');
}
// Decrypt using NaCl box open
const decrypted = nacl.box.open(encrypted, nonce, senderPublicCurve, recipientSecretCurve);
if (!decrypted) {
throw new Error('Decryption failed');
}
const contentString = new Buffer(decrypted).toString('utf-8');
const content: Content = JSON.parse(contentString);
return content;
}
/**
* Encrypt a string content using sender's private key and recipient's public key.
* @param senderSecretKey The sender's secret key.
* @param recipientPublicKey The recipient's public key.
* @param content The string to encrypt.
* @returns Promise<Uint8Array> The encrypted data.
*/
export async function encryptContent(
senderSecretKey: Buffer,
recipientPublicKey: Buffer,
content: string,
): Promise<Uint8Array> {
const contentBuffer = new Uint8Array(Buffer.from(content, 'utf-8'));
// Convert Ed25519 keys to Curve25519
const senderSecretCurve = ed2curve.convertSecretKey(senderSecretKey);
const recipientPublicCurve = ed2curve.convertPublicKey(recipientPublicKey);
if (!senderSecretCurve || !recipientPublicCurve) {
throw new Error('Invalid key conversion');
}
const nonceBuffer = await getSecureRandomBytes(24);
const nonce = new Uint8Array(nonceBuffer);
const encrypted = nacl.box(contentBuffer, nonce, recipientPublicCurve, senderSecretCurve);
const combined = new Uint8Array(nonce.length + encrypted.length);
combined.set(nonce, 0);
combined.set(encrypted, nonce.length);
return combined;
}
/**
* Decrypt encrypted content using recipient's private key and sender's public key.
* @param recipientSecretKey The recipient's secret key.
* @param senderPublicKey The sender's public key.
* @param encrypted The encrypted data.
* @returns Promise<string> The decrypted string.
*/
export async function decryptContent(
recipientSecretKey: Buffer,
senderPublicKey: Buffer,
encrypted: Uint8Array,
): Promise<string> {
// Convert Ed25519 keys to Curve25519
const recipientSecretCurve = ed2curve.convertSecretKey(recipientSecretKey);
const senderPublicCurve = ed2curve.convertPublicKey(senderPublicKey);
if (!recipientSecretCurve || !senderPublicCurve) {
throw new Error('Invalid key conversion');
}
const nonce = encrypted.slice(0, 24);
const encryptedPart = encrypted.slice(24);
const decrypted = nacl.box.open(encryptedPart, nonce, senderPublicCurve, recipientSecretCurve);
if (!decrypted) {
throw new Error('Decryption failed');
}
return new Buffer(decrypted).toString('utf-8');
}