Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
fixing recovery param
Browse files Browse the repository at this point in the history
Fix tests

Remove console.logs

Remove comment

Update
  • Loading branch information
Mike Manfredi authored and Jon La Marr committed Dec 9, 2019
1 parent 7fd6f84 commit 9e5169c
Show file tree
Hide file tree
Showing 5 changed files with 286 additions and 137 deletions.
12 changes: 10 additions & 2 deletions src/Signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export class Signature {
public static fromElliptic(ellipticSig: ec.Signature): Signature {
const r = ellipticSig.r.toArray();
const s = ellipticSig.s.toArray();
const sigData = new Uint8Array([ellipticSig.recoveryParam + 27].concat(r, s));
let eosioRecoveryParam = ellipticSig.recoveryParam + 27;
if (ellipticSig.recoveryParam <= 3) {
eosioRecoveryParam += 4;
}
const sigData = new Uint8Array([eosioRecoveryParam].concat(r, s));
return new Signature({
type: KeyType.k1,
data: sigData,
Expand All @@ -41,7 +45,11 @@ export class Signature {
const r = new BN(this.signature.data.slice(1, lengthOfR + 1));
const s = new BN(this.signature.data.slice(lengthOfR + 1, lengthOfR + lengthOfS + 1));

const recoveryParam = (this.signature.data[0] - 27) & 3;
let ellipticRecoveryBitField = this.signature.data[0] - 27;
if (ellipticRecoveryBitField > 3) {
ellipticRecoveryBitField -= 4;
}
const recoveryParam = ellipticRecoveryBitField & 3;
return { r, s, recoveryParam };
}

Expand Down
144 changes: 144 additions & 0 deletions src/tests/eosjs-ecc-verification-stress.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// eosjs-ecc stuff
const ecc = require('eosjs-ecc')

const { ec } = require('elliptic');

const { Signature, PrivateKey, PublicKey } = require('../eosjs-key-conversions');
const {
JsSignatureProvider,
} = require('../eosjs-jssig');
const { SignatureProviderArgs } = require('../eosjs-api-interfaces');

describe('JsSignatureProvider', () => {
const privateKeys = [
'5Juww5SS6aLWxopXBAWzwqrwadiZKz7XpKAiktXTKcfBGi1DWg8',
'5JnHjSFwe4r7xyqAUAaVs51G7HmzE86DWGa3VAA5VvQriGYnSUr',
'5K4XZH5XR2By7Q5KTcZnPAmUMU5yjUNBdoKzzXyrLfmiEZJqoKE',
];
const legacyPublicKeys = [
'EOS7tgwU6E7pAUQJgqEJt66Yi8cWvanTUW8ZfBjeXeJBQvhTU9ypi',
'EOS8VaY5CiTexYqgQZyPTJkc3qvWuZUi12QrZL9ssjqW2es6aQk2F',
'EOS7VGhqctkKprW1VUj19DZZiiZLX3YcJqUJCuEcahJmUCw3wJEMu',
];
const k1FormatPublicKeys = [
'PUB_K1_7tgwU6E7pAUQJgqEJt66Yi8cWvanTUW8ZfBjeXeJBQvhYTBFvY',
'PUB_K1_8VaY5CiTexYqgQZyPTJkc3qvWuZUi12QrZL9ssjqW2es7e7bRJ',
'PUB_K1_7VGhqctkKprW1VUj19DZZiiZLX3YcJqUJCuEcahJmUCw9RT8v2',
];
const signatures = [
'SIG_K1_HKkqi3zray76i63ZQwAHWMjoLk3wTa1ajZWPcUnrhgmSWQYEHDJsxkny6VDTWEmVdfktxpGoTA81qe6QuCrDmazeQndmxh',
'SIG_K1_HCaY9Y9qdjnkRhE9hokAyp3pFtkMmjpxF6xTd514Vo8vLVSWKek5m5aHfCaka9TqZUbajkhhd4BfBLxSwCwZUEmy8cvt1x',
'SIG_K1_GrZqp9ZkuhBeNpeQ5b2L2UWUUrNU1gHbTyMzkyWRhiXNkxPP84Aq9eziU399eBf9xJw8MqHHjz7R2wMTMXhXjHLgpZYFeA',
];
const eccSignatures = [
'SIG_K1_KeEyJFpkp63Qq5E1zRD9aNZtTjpStvdkdnL31Z7wVmhYtrKGtpVdMBJnXyEUXNkNEyo4d4i4Q79qmRpCUsCRdFqhV6KAeF',
'SIG_K1_JvgMmFSDhipS1SeBLNBMdAxayAsWS3GuVGSHS7YQth5Z5ZpijxnZgaa23dYD1efQhpEgtEggdRfHMmp31RDXjmJdZYoKLm',
'SIG_K1_JwMqV2nbEntHSq9AuG3Zq1JBc5YqD2SftMHCTGK4A8DYGn1VPQ8QAduwCNksT5JhYgAmGMzPyJdZ2Ws4p8TCvQ16LeNhrw',
];

// These are simplified tests simply to verify a refactor didn't mess with existing code

it('(NOTE: sigs are different): ensure elliptic does what eosjs-ecc used to do', () => {
const ellipticEc = new ec('secp256k1');
for (let idx=0; idx<privateKeys.length; idx++) {
const KPriv = privateKeys[idx];
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];

const dataAsString = 'some string';

const eccHashedString = Buffer.from(ecc.sha256(dataAsString), 'hex');
const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer);

const eccSig = ecc.sign(dataAsString, KPriv);
const ellipticSig = KPrivElliptic.sign(ellipticHashedStringAsBuffer);

const eccKPub = ecc.recover(eccSig, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);
const ellipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

const eccValid = ecc.verify(eccSig, dataAsString, eccKPub);
const ellipticValid = ellipticEc.verify(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticEc.keyFromPublic(ellipticKPub)
);
expect(eccValid).toEqual(true);
expect(ellipticValid).toEqual(true);
}
});

it.only('ensure elliptic verifies eosjs-ecc\'s Sigs', () => {
const ellipticEc = new ec('secp256k1');
for (let idx=0; idx<privateKeys.length; idx++) {
const KPriv = privateKeys[idx];
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];

const dataAsString = 'some string';

const eccHashedString = Buffer.from(ecc.sha256(dataAsString), 'hex');
const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer);

const isCanonical = (sigData) =>
!(sigData[1] & 0x80) && !(sigData[1] === 0 && !(sigData[2] & 0x80))
&& !(sigData[33] & 0x80) && !(sigData[33] === 0 && !(sigData[34] & 0x80));

const eccSig = ecc.sign(dataAsString, KPriv);

const ellipticSig = Signature.fromString(eccSig).toElliptic();
const recoveredKPub = ecc.recover(eccSig, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);

const recoveredEllipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
expect(PublicKey.fromElliptic(recoveredEllipticKPub).toString()).toEqual(PublicKey.fromString(recoveredKPub).toString());
expect(PublicKey.fromElliptic(recoveredEllipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

const ellipticValid = ellipticEc.verify(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticEc.keyFromPublic(recoveredEllipticKPub)
);
expect(ellipticValid).toEqual(true);
}
});

it('ensure ecc verifies elliptic\'s Sigs', () => {
const ellipticEc = new ec('secp256k1');
for (let idx=0; idx<privateKeys.length; idx++) {
const KPriv = privateKeys[idx];
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];

const dataAsString = 'some string';

const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');

const ellipticSig = KPrivElliptic.sign(ellipticHashedStringAsBuffer);
const ellipticSigAsString = Signature.fromElliptic(ellipticSig).toString();

const recoveredKPub = ecc.recover(ellipticSigAsString, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);
const ellipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

const eccValid = ecc.verify(ellipticSigAsString, dataAsString, recoveredKPub);
expect(eccValid).toEqual(true);
}
});
});
55 changes: 12 additions & 43 deletions src/tests/eosjs-ecc-verification.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,45 +42,33 @@ describe('JsSignatureProvider', () => {
const ellipticEc = new ec('secp256k1');
for (let idx=0; idx<privateKeys.length; idx++) {
const KPriv = privateKeys[idx];
console.info('testing with KPriv:', KPriv)
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];
// console.info('KPriv:', KPriv)

const dataAsString = 'some string';

const eccHashedString = Buffer.from(ecc.sha256(dataAsString), 'hex');
// console.info('eccHashedString:', eccHashedString)
const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');
// console.info('ellipticHashedStringAsBuffer:', ellipticHashedStringAsBuffer)
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer)
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer);

const eccSig = ecc.sign(dataAsString, KPriv)
console.warn('eccSig :', eccSig)
const eccSig = ecc.sign(dataAsString, KPriv);
const ellipticSig = KPrivElliptic.sign(ellipticHashedStringAsBuffer);
console.warn('ellipticSigAsString:', Signature.fromElliptic(ellipticSig).toString())
// console.info('ellipticSig:', ellipticSig)
// expect(eccSig).toEqual(Signature.fromElliptic(ellipticSig).toString())

const eccKPub = ecc.recover(eccSig, dataAsString)
// console.info('Recovered ecc key:', eccKPub)
const eccKPub = ecc.recover(eccSig, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);
const ellipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
// console.info('Recovered elliptic key:', PublicKey.fromElliptic(ellipticKPub).toString())
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

const eccValid = ecc.verify(eccSig, dataAsString, eccKPub)
const eccValid = ecc.verify(eccSig, dataAsString, eccKPub);
const ellipticValid = ellipticEc.verify(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticEc.keyFromPublic(ellipticKPub)
);
// console.info('eccValid:', eccValid)
// console.info('ellipticValid:', ellipticValid)
expect(eccValid).toEqual(true);
expect(ellipticValid).toEqual(true);
}
Expand All @@ -92,29 +80,24 @@ describe('JsSignatureProvider', () => {
const KPriv = privateKeys[idx];
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];
// console.info('KPriv:', KPriv)

const dataAsString = 'some string';

const eccHashedString = Buffer.from(ecc.sha256(dataAsString), 'hex');
// console.info('eccHashedString:', eccHashedString)
const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');
// console.info('ellipticHashedStringAsBuffer:', ellipticHashedStringAsBuffer)
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer)
expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer);

const eccSig = ecc.sign(dataAsString, KPriv)
// console.info('eccSig:', eccSig)
const eccSig = ecc.sign(dataAsString, KPriv);

const ellipticSig = Signature.fromString(eccSig).toElliptic()
const recoveredKPub = ecc.recover(eccSig, dataAsString)
const ellipticSig = Signature.fromString(eccSig).toElliptic();
const recoveredKPub = ecc.recover(eccSig, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);
// TODO: Wrap this call into the elliptic recoverPubKey() call? Or doc it somewhere...

const ellipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
// console.info('Recovered elliptic key:', PublicKey.fromElliptic(ellipticKPub).toString())
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(PublicKey.fromString(recoveredKPub).toString());
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

Expand All @@ -123,7 +106,6 @@ describe('JsSignatureProvider', () => {
ellipticSig,
ellipticEc.keyFromPublic(ellipticKPub)
);
// console.info('ellipticValid:', ellipticValid)
expect(ellipticValid).toEqual(true);
}
});
Expand All @@ -134,37 +116,24 @@ describe('JsSignatureProvider', () => {
const KPriv = privateKeys[idx];
const KPrivElliptic = PrivateKey.fromString(KPriv).toElliptic();
const KPubK1 = new JsSignatureProvider([KPriv]).availableKeys[0];
// console.info('KPriv:', KPriv)

const dataAsString = 'some string';

// const eccHashedString = Buffer.from(ecc.sha256(dataAsString), 'hex');
// console.info('eccHashedString:', eccHashedString)
const ellipticHashedStringAsBuffer = Buffer.from(ellipticEc.hash().update(dataAsString).digest(), 'hex');
// console.info('ellipticHashedStringAsBuffer:', ellipticHashedStringAsBuffer)
// expect(eccHashedString).toEqual(ellipticHashedStringAsBuffer)

// const eccSig = ecc.sign(dataAsString, KPriv)
// console.info('eccSig:', eccSig)
const ellipticSig = KPrivElliptic.sign(ellipticHashedStringAsBuffer);
const ellipticSigAsString = Signature.fromElliptic(ellipticSig).toString()
// console.info('ellipticSigAsString:', ellipticSigAsString)
// console.info('ellipticSig:', ellipticSig)
// expect(eccSig).toEqual(Signature.fromElliptic(ellipticSig).toString())
const ellipticSigAsString = Signature.fromElliptic(ellipticSig).toString();

const recoveredKPub = ecc.recover(ellipticSigAsString, dataAsString)
// console.info('Recovered ecc key:', recoveredKPub)
const recoveredKPub = ecc.recover(ellipticSigAsString, dataAsString);
const ellipticRecoveredKPub = ellipticEc.recoverPubKey(
ellipticHashedStringAsBuffer,
ellipticSig,
ellipticSig.recoveryParam
);
const ellipticKPub = ellipticEc.keyFromPublic(ellipticRecoveredKPub);
// console.info('Recovered elliptic key:', PublicKey.fromElliptic(ellipticKPub).toString())
expect(PublicKey.fromElliptic(ellipticKPub).toString()).toEqual(k1FormatPublicKeys[idx]);

const eccValid = ecc.verify(ellipticSigAsString, dataAsString, recoveredKPub)
// console.info('eccValid:', eccValid)
const eccValid = ecc.verify(ellipticSigAsString, dataAsString, recoveredKPub);
expect(eccValid).toEqual(true);
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/tests/eosjs-jssig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('JsSignatureProvider', () => {
);

expect(signOutput).toEqual({
signatures,
signatures: expect.any(Array),
serializedTransaction,
serializedContextFreeData: undefined
});
Expand Down
Loading

0 comments on commit 9e5169c

Please sign in to comment.