Skip to content

Commit

Permalink
Extend the key.verify function to accept prefixSigs
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewKishino committed May 30, 2020
1 parent 64046c5 commit 7541b0f
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 75 deletions.
2 changes: 1 addition & 1 deletion dist/node/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/web/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const extractKeys = (sk, password = '') => __awaiter(void 0, void 0, void
throw new Error(e);
}
const sodium = _sodium;
const curve = sk.substr(0, 2);
const curve = sk.substring(0, 2);
if (![54, 55, 88, 98].includes(sk.length)) {
throw new Error('Invalid length for a key encoding');
}
Expand Down
12 changes: 6 additions & 6 deletions lib/forge.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ export const parameters = (parameter, protocol) => {
* @returns {string} Forged public key hash bytes
*/
export const publicKeyHash = (pkh) => {
const t = parseInt(pkh.substr(2, 1), 10);
const t = parseInt(pkh.substring(2, 1), 10);
const fpkh = [`0${t - 1}`];
const forgedBuffer = toBuffer(b58cdecode(pkh, prefix[pkh.substr(0, 3)]));
const forgedBuffer = toBuffer(b58cdecode(pkh, prefix[pkh.substring(0, 3)]));
fpkh.push(buf2hex(forgedBuffer));
return fpkh.join('');
};
Expand All @@ -130,11 +130,11 @@ export const address = (addressArg, protocol = '') => {
};
const getAddressType = (a) => {
if (!protocol || addressSourceBytes[protocol]) {
return a.substr(0, 1) === 'K' ? '01' : '00';
return a.substring(0, 1) === 'K' ? '01' : '00';
}
return '';
};
if (addressArg.substr(0, 1) === 'K') {
if (addressArg.substring(0, 1) === 'K') {
fa.push(getAddressType(addressArg));
const forgedBuffer = toBuffer(b58cdecode(addressArg, prefix.KT));
fa.push(buf2hex(forgedBuffer));
Expand Down Expand Up @@ -182,7 +182,7 @@ export const zarith = (n) => {
*/
export const publicKey = (pk) => {
const fpk = [];
switch (pk.substr(0, 2)) {
switch (pk.substring(0, 2)) {
case 'ed':
fpk.push('00');
break;
Expand All @@ -195,7 +195,7 @@ export const publicKey = (pk) => {
default:
break;
}
const forgedBuffer = toBuffer(b58cdecode(pk, prefix[pk.substr(0, 4)]));
const forgedBuffer = toBuffer(b58cdecode(pk, prefix[pk.substring(0, 4)]));
fpk.push(buf2hex(forgedBuffer));
return fpk.join('');
};
Expand Down
38 changes: 24 additions & 14 deletions lib/key.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,17 @@ export class Key {
ready();
return;
}
this._curve = key.substr(0, 2);
this._curve = key.substring(0, 2);
if (!['sp', 'p2', 'ed'].includes(this._curve)) {
throw new Error('Invalid prefix for a key encoding.');
}
if (![54, 55, 88, 98].includes(key.length)) {
throw new Error('Invalid length for a key encoding');
}
const encrypted = key.substring(2, 3) === 'e';
const publicOrSecret = encrypted ? key.slice(3, 5) : key.slice(2, 4);
const publicOrSecret = encrypted
? key.substring(3, 5)
: key.substring(2, 4);
if (!['pk', 'sk'].includes(publicOrSecret)) {
throw new Error('Invalid prefix for a key encoding.');
}
Expand Down Expand Up @@ -140,15 +142,13 @@ export class Key {
else if (this._curve === 'sp') {
const keyPair = new elliptic.ec('secp256k1').keyFromPrivate(constructedKey);
const prefixVal = keyPair.getPublic().getY().toArray()[31] % 2 ? 3 : 2;
// Need to pad keypair array to maintain a length of 32
const pad = [0, 0];
const pad = new Array(32).fill(0);
this._publicKey = toBuffer(new Uint8Array([prefixVal].concat(pad.concat(keyPair.getPublic().getX().toArray()).slice(-32))));
}
else if (this._curve === 'p2') {
const keyPair = new elliptic.ec('p256').keyFromPrivate(constructedKey);
const prefixVal = keyPair.getPublic().getY().toArray()[31] % 2 ? 3 : 2;
// Need to pad keypair array to maintain a length of 32
const pad = [0, 0];
const pad = new Array(32).fill(0);
this._publicKey = toBuffer(new Uint8Array([prefixVal].concat(pad.concat(keyPair.getPublic().getX().toArray()).slice(-32))));
}
else {
Expand Down Expand Up @@ -239,24 +239,34 @@ export class Key {
if (!publicKey) {
throw new Error('Cannot verify without a public key');
}
const _publicKey = toBuffer(b58cdecode(publicKey, prefix[`${this._curve}pk`]));
if (signature.slice(0, 3) !== 'sig') {
if (this._curve !== signature.slice(0, 2)) {
const _curve = publicKey.substring(0, 2);
const _publicKey = toBuffer(b58cdecode(publicKey, prefix[`${_curve}pk`]));
if (signature.substring(0, 3) !== 'sig') {
if (_curve !== signature.substring(0, 2)) {
// 'sp', 'p2' 'ed'
throw new Error('Signature and public key curves mismatch.');
}
}
const bytesBuffer = sodium.crypto_generichash(32, hex2buf(bytes));
const sig = b58cdecode(signature, prefix.sig);
if (this._curve === 'ed') {
let sig;
if (signature.substring(0, 3) === 'sig') {
sig = b58cdecode(signature, prefix.sig);
}
else if (signature.substring(0, 5) === `${_curve}sig`) {
sig = b58cdecode(signature, prefix[`${_curve}sig`]);
}
else {
throw new Error(`Invalid signature provided: ${signature}`);
}
if (_curve === 'ed') {
try {
return sodium.crypto_sign_verify_detached(sig, bytesBuffer, _publicKey);
}
catch (e) {
return false;
}
}
else if (this._curve === 'sp') {
else if (_curve === 'sp') {
const key = new elliptic.ec('secp256k1').keyFromPublic(_publicKey);
const formattedSig = buf2hex(toBuffer(sig));
const match = formattedSig.match(/([a-f\d]{64})/gi);
Expand All @@ -271,7 +281,7 @@ export class Key {
}
return false;
}
else if (this._curve === 'p2') {
else if (_curve === 'p2') {
const key = new elliptic.ec('p256').keyFromPublic(_publicKey);
const formattedSig = buf2hex(toBuffer(sig));
const match = formattedSig.match(/([a-f\d]{64})/gi);
Expand All @@ -287,7 +297,7 @@ export class Key {
return false;
}
else {
throw new Error(`Curve '${this._curve}' not supported`);
throw new Error(`Curve '${_curve}' not supported`);
}
};
this._isLedger = !key;
Expand Down
2 changes: 1 addition & 1 deletion lib/utility.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const sexp2mic = function me(mi) {
ret.args.push({ int: val });
}
else if (val[0] === '0' && val[1] === 'x') {
val = val.substr(2);
val = val.substring(2);
if (!ret.prim)
return { bytes: val };
ret.args.push({ bytes: val });
Expand Down
35 changes: 13 additions & 22 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"xhr2": "^0.2.0"
},
"devDependencies": {
"@types/bip39": "^3.0.0",
"@types/detect-node": "^2.0.0",
"@types/elliptic": "^6.4.9",
"@types/ledgerhq__hw-transport": "^4.21.2",
Expand Down
2 changes: 1 addition & 1 deletion src/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const extractKeys = async (sk: string, password = ''): Promise<Keys> => {

const sodium = _sodium;

const curve = sk.substr(0, 2);
const curve = sk.substring(0, 2);

if (![54, 55, 88, 98].includes(sk.length)) {
throw new Error('Invalid length for a key encoding');
Expand Down
12 changes: 6 additions & 6 deletions src/forge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ export const parameters = (parameter: any, protocol: string): string => {
* @returns {string} Forged public key hash bytes
*/
export const publicKeyHash = (pkh: string): string => {
const t = parseInt(pkh.substr(2, 1), 10);
const t = parseInt(pkh.substring(2, 1), 10);
const fpkh = [`0${t - 1}`];
const forgedBuffer = toBuffer(b58cdecode(pkh, prefix[pkh.substr(0, 3)]));
const forgedBuffer = toBuffer(b58cdecode(pkh, prefix[pkh.substring(0, 3)]));
fpkh.push(buf2hex(forgedBuffer));
return fpkh.join('');
};
Expand All @@ -221,12 +221,12 @@ export const address = (addressArg: string, protocol = ''): string => {

const getAddressType = (a: string): string => {
if (!protocol || addressSourceBytes[protocol]) {
return a.substr(0, 1) === 'K' ? '01' : '00';
return a.substring(0, 1) === 'K' ? '01' : '00';
}
return '';
};

if (addressArg.substr(0, 1) === 'K') {
if (addressArg.substring(0, 1) === 'K') {
fa.push(getAddressType(addressArg));
const forgedBuffer = toBuffer(b58cdecode(addressArg, prefix.KT));
fa.push(buf2hex(forgedBuffer));
Expand Down Expand Up @@ -273,7 +273,7 @@ export const zarith = (n: string): string => {
*/
export const publicKey = (pk: string): string => {
const fpk: Array<string> = [];
switch (pk.substr(0, 2)) {
switch (pk.substring(0, 2)) {
case 'ed':
fpk.push('00');
break;
Expand All @@ -286,7 +286,7 @@ export const publicKey = (pk: string): string => {
default:
break;
}
const forgedBuffer = toBuffer(b58cdecode(pk, prefix[pk.substr(0, 4)]));
const forgedBuffer = toBuffer(b58cdecode(pk, prefix[pk.substring(0, 4)]));
fpk.push(buf2hex(forgedBuffer));
return fpk.join('');
};
Expand Down
32 changes: 20 additions & 12 deletions src/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export class Key {
return;
}

this._curve = key.substr(0, 2);
this._curve = key.substring(0, 2);

if (!['sp', 'p2', 'ed'].includes(this._curve)) {
throw new Error('Invalid prefix for a key encoding.');
Expand All @@ -191,7 +191,9 @@ export class Key {
}

const encrypted = key.substring(2, 3) === 'e';
const publicOrSecret = encrypted ? key.slice(3, 5) : key.slice(2, 4);
const publicOrSecret = encrypted
? key.substring(3, 5)
: key.substring(2, 4);

if (!['pk', 'sk'].includes(publicOrSecret)) {
throw new Error('Invalid prefix for a key encoding.');
Expand Down Expand Up @@ -388,27 +390,33 @@ export class Key {
throw new Error('Cannot verify without a public key');
}

const _publicKey = toBuffer(
b58cdecode(publicKey, prefix[`${this._curve}pk`]),
);
const _curve = publicKey.substring(0, 2);
const _publicKey = toBuffer(b58cdecode(publicKey, prefix[`${_curve}pk`]));

if (signature.slice(0, 3) !== 'sig') {
if (this._curve !== signature.slice(0, 2)) {
if (signature.substring(0, 3) !== 'sig') {
if (_curve !== signature.substring(0, 2)) {
// 'sp', 'p2' 'ed'
throw new Error('Signature and public key curves mismatch.');
}
}

const bytesBuffer = sodium.crypto_generichash(32, hex2buf(bytes));
const sig = b58cdecode(signature, prefix.sig);
let sig;
if (signature.substring(0, 3) === 'sig') {
sig = b58cdecode(signature, prefix.sig);
} else if (signature.substring(0, 5) === `${_curve}sig`) {
sig = b58cdecode(signature, prefix[`${_curve}sig`]);
} else {
throw new Error(`Invalid signature provided: ${signature}`);
}

if (this._curve === 'ed') {
if (_curve === 'ed') {
try {
return sodium.crypto_sign_verify_detached(sig, bytesBuffer, _publicKey);
} catch (e) {
return false;
}
} else if (this._curve === 'sp') {
} else if (_curve === 'sp') {
const key = new elliptic.ec('secp256k1').keyFromPublic(_publicKey);
const formattedSig = buf2hex(toBuffer(sig));
const match = formattedSig.match(/([a-f\d]{64})/gi);
Expand All @@ -421,7 +429,7 @@ export class Key {
}
}
return false;
} else if (this._curve === 'p2') {
} else if (_curve === 'p2') {
const key = new elliptic.ec('p256').keyFromPublic(_publicKey);
const formattedSig = buf2hex(toBuffer(sig));
const match = formattedSig.match(/([a-f\d]{64})/gi);
Expand All @@ -435,7 +443,7 @@ export class Key {
}
return false;
} else {
throw new Error(`Curve '${this._curve}' not supported`);
throw new Error(`Curve '${_curve}' not supported`);
}
};
}
2 changes: 1 addition & 1 deletion src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export const sexp2mic = function me(mi: string): Micheline {
if (!ret.prim) return { int: val };
ret.args.push({ int: val });
} else if (val[0] === '0' && val[1] === 'x') {
val = val.substr(2);
val = val.substring(2);
if (!ret.prim) return { bytes: val };
ret.args.push({ bytes: val });
} else if (ret.prim) {
Expand Down
Loading

0 comments on commit 7541b0f

Please sign in to comment.