Initial commit
This commit is contained in:
191
benchmarks/diffie-helman.ts
Normal file
191
benchmarks/diffie-helman.ts
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user