I'm trying to create a simple cryptocurrency for which I made a wallet in Node.JS using the bip39 and crypto module. The plan is to be able to create a wallet so that the script generates a random mnemonic phrase and from that a private and public key. The same mnemonic should result in the same key pair, while different mnemonics should result in different pairs.
For some reason, if after generation I try to generate the same private/public key from the same mnemonic as before, a different key pair is returned. I'm just learning cryptography, I might be doing something very wrong. Anyway, thanks in advance for your help, here is my code:
function generateRandomMnemonic() {
// Generate a random 256-bit (32-byte) entropy
const entropy = crypto.randomBytes(32);
// Convert the entropy to a mnemonic phrase
const mnemonic = bip39.entropyToMnemonic(entropy);
return mnemonic;
}
function generateKeyPairFromMnemonic(mnemonic) {
// Derive a seed from the mnemonic phrase
const seed = bip39.mnemonicToSeedSync(mnemonic);
// Generate key pair from the seed
const keyPair = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
},
seed,
});
return keyPair;
}
function getAddress(publicKey) {
const addressHash = crypto.createHash('sha256').update(publicKey).digest('hex').slice(-30);
return `csc.${addressHash}`
}
function signTransaction(transaction, privateKey) {
const dataToSign = JSON.stringify(transaction);
// Sign the data correctly
const sign = crypto.createSign('sha256');
sign.update(JSON.stringify(transaction));
const signature = sign.sign(privateKey, 'base64');
return signature;
}
The code where the wallet is generated:
app.get('/signup', async (req, res) => {
const mnemonic = generateRandomMnemonic();
const keypair = generateKeyPairFromMnemonic(mnemonic);
const address = getAddress(keypair.publicKey);
console.log("Generated address: ", address);
req.session.mnemonic = mnemonic;
req.session.address = address;
res.render(DIRECTORY + "/register.html", {mnemonic:mnemonic});
});
app.get('/signin', async (req, res) => {
res.render(DIRECTORY + "/login.html");
});
app.post('/signin', async (req, res) => {
let mnemonic = req.body.mnemonic;
const keypair = generateKeyPairFromMnemonic(mnemonic);
const address = getAddress(keypair.publicKey);
req.session.mnemonic = mnemonic;
req.session.address = address;
res.redirect('/success');
});
Should I use elliptic curve instead?
const bip39 = require('bip39');
const crypto = require('crypto');
const elliptic = require('elliptic');
function generateKeyPairFromMnemonic(mnemonic) {
// Derive a seed from the mnemonic phrase
const seed = bip39.mnemonicToSeedSync(mnemonic);
// Create an elliptic curve key pair
const ec = new elliptic.ec('secp256k1');
const keyPair = ec.genKeyPair({
entropy: seed.slice(0, 32), // Take the first 32 bytes of the seed for entropy
});
return {
privateKey: keyPair.getPrivate('hex'),
publicKey: keyPair.getPublic('hex'),
};
}
// Example usage
const mnemonic = 'your twelve word mnemonic phrase';
const keyPair = generateKeyPairFromMnemonic(mnemonic);
console.log('Private Key:', keyPair.privateKey);
console.log('Public Key:', keyPair.publicKey);