@smartledger/elliptic-fix
Version:
Security fix for signature malleability vulnerability in Elliptic package v6.5.5 used by bsv@1.5.6
68 lines (55 loc) • 2.55 kB
JavaScript
const elliptic = require('elliptic');
const BN = require('bn.js');
const ed = new elliptic.eddsa('ed25519');
// Test data
const key = ed.keyFromSecret('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef');
const msg = Buffer.from('test message');
// Create a valid signature
const validSig = key.sign(msg);
// Create a malleable signature by modifying the internal representation
const validSigBytes = Buffer.from(validSig.toHex(), 'hex');
const R = validSigBytes.slice(0, 32); // First 32 bytes are R
// Create a malleable S value just slightly larger than the curve order
const curveOrder = ed.curve.n;
const malleableS = curveOrder.addn(1); // n + 1
const malleableSBytes = malleableS.toArrayLike(Buffer, 'le', 32);
// Combine R and malleable S
const malleableSig = Buffer.concat([R, malleableSBytes]);
const malleableSigHex = malleableSig.toString('hex');
console.log('\nTesting signature malleability vulnerability:');
console.log('Curve order:', curveOrder.toString(16));
console.log('Malleable S value:', malleableS.toString(16));
console.log('Is S >= curve order?', malleableS.gte(curveOrder));
// Store original verify function
const originalVerify = ed.verify;
console.log('\nOriginal behavior (without fix):');
console.log('Valid signature verification:', originalVerify.call(ed, msg, validSig.toHex(), key.getPublic()));
try {
console.log('Malleable signature verification:', originalVerify.call(ed, msg, malleableSigHex, key.getPublic()));
} catch (e) {
console.log('Malleable signature failed:', e.message);
}
// Apply our fix to the verify function
ed.verify = function patchedVerify(message, sig, pub) {
try {
const signature = this.makeSignature(sig);
const S = signature.S();
// Check if S is >= curve order or negative
if (S.gte(this.curve.n) || S.isNeg()) {
console.log('Rejecting signature: S value is >= curve order or negative');
return false;
}
// If S is valid, proceed with original verification
return originalVerify.call(this, message, sig, pub);
} catch (e) {
console.log('Invalid signature format:', e.message);
return false;
}
};
console.log('\nBehavior with fix applied:');
console.log('Valid signature verification:', ed.verify(msg, validSig.toHex(), key.getPublic()));
try {
console.log('Malleable signature verification:', ed.verify(msg, malleableSigHex, key.getPublic()));
} catch (e) {
console.log('Malleable signature failed:', e.message);
}