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);
}