Initial commit

This commit is contained in:
2025-08-16 16:11:33 +10:00
commit 91df32c786
39 changed files with 6284 additions and 0 deletions

191
benchmarks/diffie-helman.ts Normal file
View File

@@ -0,0 +1,191 @@
/**
* Pure TypeScript implementation of Diffie-Hellman key exchange
*
* Uses MODP Group 14 (RFC 3526) parameters:
* - 2048-bit prime modulus
* - Generator = 2
*/
// MODP Group 14 parameters (RFC 3526)
const PRIME_2048 = BigInt(
'0x' +
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' +
'29024E088A67CC74020BBEA63B139B22514A08798E3404DD' +
'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' +
'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' +
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D' +
'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F' +
'83655D23DCA3AD961C62F356208552BB9ED529077096966D' +
'670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF',
);
const GENERATOR = BigInt(2);
/**
* Convert Uint8Array to BigInt
*/
function uint8ArrayToBigInt(bytes: Uint8Array): bigint {
let result = BigInt(0);
for (let i = 0; i < bytes.length; i++) {
result = (result << BigInt(8)) + BigInt(bytes[i]);
}
return result;
}
/**
* Convert BigInt to Uint8Array of specified length
*/
function bigIntToUint8Array(value: bigint, byteLength: number): Uint8Array {
const result = new Uint8Array(byteLength);
let temp = value;
for (let i = byteLength - 1; i >= 0; i--) {
result[i] = Number(temp & BigInt(0xff));
temp = temp >> BigInt(8);
}
return result;
}
/**
* Modular exponentiation: (base^exponent) mod modulus
* Uses binary exponentiation for efficiency
*/
function modPow(base: bigint, exponent: bigint, modulus: bigint): bigint {
if (modulus === BigInt(1)) return BigInt(0);
let result = BigInt(1);
base = base % modulus;
while (exponent > BigInt(0)) {
if (exponent % BigInt(2) === BigInt(1)) {
result = (result * base) % modulus;
}
exponent = exponent >> BigInt(1);
base = (base * base) % modulus;
}
return result;
}
/**
* Generate a Diffie-Hellman public key from a private key
*
* @param privateKey - Private key as Uint8Array (should be random and less than the prime)
* @returns Public key as Uint8Array
*/
export function generatePublicKey(privateKey: Uint8Array): Uint8Array {
const privateKeyBigInt = uint8ArrayToBigInt(privateKey);
const publicKeyBigInt = modPow(GENERATOR, privateKeyBigInt, PRIME_2048);
return bigIntToUint8Array(publicKeyBigInt, 256); // 2048 bits = 256 bytes
}
/**
* Compute Diffie-Hellman shared secret
*
* @param privateKey - Your private key as Uint8Array
* @param publicKey - Other party's public key as Uint8Array
* @returns Shared secret as Uint8Array
*/
export function diffieHellman(
privateKey: Uint8Array,
publicKey: Uint8Array,
): Uint8Array {
const privateKeyBigInt = uint8ArrayToBigInt(privateKey);
const publicKeyBigInt = uint8ArrayToBigInt(publicKey);
// Validate that the public key is valid (1 < publicKey < prime-1)
if (
publicKeyBigInt <= BigInt(1) ||
publicKeyBigInt >= PRIME_2048 - BigInt(1)
) {
throw new Error('Invalid public key: must be between 1 and prime-1');
}
// Compute shared secret: (publicKey^privateKey) mod prime
const sharedSecretBigInt = modPow(
publicKeyBigInt,
privateKeyBigInt,
PRIME_2048,
);
return bigIntToUint8Array(sharedSecretBigInt, 256); // 2048 bits = 256 bytes
}
/**
* Generate a random private key suitable for Diffie-Hellman
*
* @returns Random private key as Uint8Array
*/
export function generatePrivateKey(): Uint8Array {
// Generate a random 256-byte private key
// In practice, you'd use crypto.getRandomValues() but since this is pure TS:
const privateKey = new Uint8Array(256);
// Simple pseudo-random generation (NOT cryptographically secure)
// In real applications, use crypto.getRandomValues() or similar
for (let i = 0; i < privateKey.length; i++) {
privateKey[i] = Math.floor(Math.random() * 256);
}
// Ensure the private key is less than the prime by clearing the most significant bit
privateKey[0] &= 0x7f;
return privateKey;
}
/**
* Complete Diffie-Hellman key exchange example
*
* @returns Object with generated keys and shared secret
*/
export function demonstrateDiffieHellman() {
// Alice generates her key pair
const alicePrivateKey = generatePrivateKey();
const alicePublicKey = generatePublicKey(alicePrivateKey);
// Bob generates his key pair
const bobPrivateKey = generatePrivateKey();
const bobPublicKey = generatePublicKey(bobPrivateKey);
// Both parties compute the same shared secret
const aliceSharedSecret = diffieHellman(alicePrivateKey, bobPublicKey);
const bobSharedSecret = diffieHellman(bobPrivateKey, alicePublicKey);
// Verify they computed the same secret
const secretsMatch = aliceSharedSecret.every(
(byte, index) => byte === bobSharedSecret[index],
);
return {
alicePrivateKey,
alicePublicKey,
bobPrivateKey,
bobPublicKey,
aliceSharedSecret,
bobSharedSecret,
secretsMatch,
};
}
// Example usage and test
if (require.main === module) {
console.log('Diffie-Hellman Key Exchange Demo');
console.log('================================');
const demo = demonstrateDiffieHellman();
console.log(
'Alice Public Key (first 8 bytes):',
Array.from(demo.alicePublicKey.slice(0, 8)),
);
console.log(
'Bob Public Key (first 8 bytes):',
Array.from(demo.bobPublicKey.slice(0, 8)),
);
console.log(
'Shared Secret (first 8 bytes):',
Array.from(demo.aliceSharedSecret.slice(0, 8)),
);
console.log('Secrets Match:', demo.secretsMatch);
}

7
benchmarks/rng.ts Normal file
View File

@@ -0,0 +1,7 @@
import crypto from 'crypto';
import { Bytes } from '../src/crypto/bytes.js';
const rng = crypto.getRandomValues(new Uint8Array(2048));
const bytes = Bytes.from(rng);
console.log(bytes.toBase64());

57
benchmarks/sekp256k1.ts Normal file
View File

@@ -0,0 +1,57 @@
import { Bytes, User } from '../src/index.js';
const alice = await User.fromSecret('alice');
const bob = await User.fromSecret('bob');
const alicePublicKey = await alice.getPublicKey();
const bobPublicKey = await bob.getPublicKey();
const keyStart = performance.now();
const aliceSharedSecret = await alice.getSharedSecret(bobPublicKey);
const bobSharedSecret = await bob.getSharedSecret(alicePublicKey);
const keyEnd = performance.now();
console.log(`Key generation time: ${keyEnd - keyStart}ms`);
const message = 'Hello, world!';
const count = 100_000;
const start = performance.now();
for (let i = 0; i < count; i++) {
// Encrypt key with shared secret
const encryptedKey = await aliceSharedSecret.encrypt(Bytes.fromUtf8(message));
// Decrypt key with shared secret
const decryptedKey = await bobSharedSecret.decrypt(encryptedKey);
if (decryptedKey.toUtf8() !== message) {
throw new Error('Decrypted message does not match original message');
}
}
const end = performance.now();
const totalTimeMs = end - start;
const operationsPerSecond = (count / totalTimeMs) * 1000;
console.log(
`Aes encrypt/decrypt per second: ${operationsPerSecond} (Total time: ${totalTimeMs}ms)`,
);
const startEncrypt = performance.now();
for (let i = 0; i < count; i++) {
// Encrypt key with shared secret
const encryptedKey = await aliceSharedSecret.encrypt(Bytes.fromUtf8(message));
}
const endEncrypt = performance.now();
const totalTimeMsEncrypt = endEncrypt - startEncrypt;
const operationsPerSecondEncrypt = (count / totalTimeMsEncrypt) * 1000;
console.log(
`Aes encrypt per second: ${operationsPerSecondEncrypt} (Total time: ${totalTimeMsEncrypt}ms)`,
);

25
benchmarks/sha256.ts Normal file
View File

@@ -0,0 +1,25 @@
import { sha256, binToBase58 } from '@bitauth/libauth';
const data = 'Hello, world!';
const count = 1_000_000;
let bytes = new TextEncoder().encode(data);
const start = performance.now();
for (let i = 0; i < count; i++) {
bytes = new Uint8Array(sha256.hash(bytes));
}
const end = performance.now();
const totalTimeMs = end - start;
const operationsPerSecond = (count / totalTimeMs) * 1000;
console.log(
`libauth sha256 per second: ${operationsPerSecond} (Total time: ${totalTimeMs}ms)`,
);
console.log(binToBase58(bytes));
if (binToBase58(bytes) !== '2YZjvhWqVKZgQFDnVkadwRcpJkqW6oNjiHPXxkEpq2zP') {
throw new Error('sha256 hash is incorrect');
}

38
benchmarks/storage.ts Normal file
View File

@@ -0,0 +1,38 @@
import { AESKey } from '../src/crypto/aes-key.js';
import { BaseStorage } from '../src/storage/base-storage.js';
import { StorageMemory, StorageMemorySynced, EncryptedStorage } from '../src/storage/index.js';
const storage = StorageMemory.from();
// const storageSynced = StorageMemorySynced.from(storage);
const currentDate = new Date();
const data = {
name: 'test',
age: 20,
email: 'test@test.com',
password: 'test',
createdAt: currentDate,
updatedAt: new Date(currentDate.getTime() + 1000),
}
const storageEncryptedBase = StorageMemory.from()
const storageEncrypted = EncryptedStorage.from(storageEncryptedBase, await AESKey.fromSeed('test'));
storageEncryptedBase.on('insert', (event) => {
console.log('insert', event);
});
// Store data in storage
await storage.insertOne('test', data);
// storageSynced.insertOne('test', data);
await storageEncrypted.insertOne('test', data);
// Retrieve data from storage
const retrievedData = await storage.findOne({ name: 'test' });
// const retrievedDataSynced = await storageSynced.findOne('test');
const retrievedDataEncrypted = await storageEncrypted.findOne({ name: 'test' });
console.log(retrievedData);
// console.log(retrievedDataSynced);
console.log(retrievedDataEncrypted);