Merge pull request #8 from 0xProject/isSignatureValid
Add isSignatureValid method and tests for it
This commit is contained in:
commit
140a160ba0
@ -1,3 +1,7 @@
|
|||||||
|
machine:
|
||||||
|
node:
|
||||||
|
version: 6.1.0
|
||||||
|
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
- npm run test:coverage
|
- npm run test:coverage
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^3.5.2",
|
"@types/chai": "^3.5.2",
|
||||||
"@types/mocha": "^2.2.41",
|
"@types/mocha": "^2.2.41",
|
||||||
|
"@types/node": "^7.0.22",
|
||||||
"awesome-typescript-loader": "^3.1.3",
|
"awesome-typescript-loader": "^3.1.3",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"mocha": "^3.4.1",
|
"mocha": "^3.4.1",
|
||||||
@ -46,5 +47,8 @@
|
|||||||
"typedoc": "^0.7.1",
|
"typedoc": "^0.7.1",
|
||||||
"typescript": "^2.3.3",
|
"typescript": "^2.3.3",
|
||||||
"webpack": "^2.6.0"
|
"webpack": "^2.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ethereumjs-util": "^5.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,31 @@
|
|||||||
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elliptic Curve signature
|
||||||
|
*/
|
||||||
|
export interface ECSignature {
|
||||||
|
v: number;
|
||||||
|
r: string;
|
||||||
|
s: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class ZeroEx {
|
export class ZeroEx {
|
||||||
/** Verifies the signature */
|
/**
|
||||||
public verifySignature() {
|
* Verifies that the elliptic curve signature `signature` was generated
|
||||||
// TODO
|
* by signing `data` with the private key corresponding to the `signer` address.
|
||||||
|
*/
|
||||||
|
public static isValidSignature(data: string, signature: ECSignature, signer: ETHAddressHex): boolean {
|
||||||
|
const dataBuff = ethUtil.toBuffer(data);
|
||||||
|
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
|
||||||
|
try {
|
||||||
|
const pubKey = ethUtil.ecrecover(msgHashBuff,
|
||||||
|
signature.v,
|
||||||
|
ethUtil.toBuffer(signature.r),
|
||||||
|
ethUtil.toBuffer(signature.s));
|
||||||
|
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
||||||
|
return retrievedAddress === signer;
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/ts/globals.d.ts
vendored
Normal file
11
src/ts/globals.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
declare type ETHPublicKey = string;
|
||||||
|
declare type ETHAddressHex = string;
|
||||||
|
declare type ETHAddressBuff = Buffer;
|
||||||
|
|
||||||
|
declare module 'ethereumjs-util' {
|
||||||
|
const toBuffer: (data: string) => Buffer;
|
||||||
|
const hashPersonalMessage: (msg: Buffer) => Buffer;
|
||||||
|
const bufferToHex: (buff: Buffer) => string;
|
||||||
|
const ecrecover: (msgHashBuff: Buffer, v: number, r: Buffer, s: Buffer) => ETHPublicKey;
|
||||||
|
const pubToAddress: (pubKey: ETHPublicKey) => ETHAddressBuff;
|
||||||
|
}
|
@ -3,10 +3,73 @@ import {expect} from 'chai';
|
|||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
describe('ZeroEx library', () => {
|
describe('ZeroEx library', () => {
|
||||||
describe('#verifySignature', () => {
|
describe('#isValidSignature', () => {
|
||||||
it('should return undefined', () => {
|
// This test data was borrowed from the JSON RPC documentation
|
||||||
const zeroEx = new ZeroEx();
|
// Source: https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
|
||||||
expect(zeroEx.verifySignature()).to.be.undefined;
|
const data = '0xdeadbeaf';
|
||||||
|
const signature = {
|
||||||
|
v: 27,
|
||||||
|
r: '0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a1',
|
||||||
|
s: '0x2d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee',
|
||||||
|
};
|
||||||
|
const address = '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83';
|
||||||
|
describe('should return false for malformed signature', () => {
|
||||||
|
it('malformed v', () => {
|
||||||
|
const malformedSignature = {
|
||||||
|
v: 34,
|
||||||
|
r: signature.r,
|
||||||
|
s: signature.s,
|
||||||
|
};
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('r lacks 0x prefix', () => {
|
||||||
|
const malformedR = signature.r.replace('0x', '');
|
||||||
|
const malformedSignature = {
|
||||||
|
v: signature.v,
|
||||||
|
r: malformedR,
|
||||||
|
s: signature.s,
|
||||||
|
};
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('r is too short', () => {
|
||||||
|
const malformedR = signature.r.substr(10);
|
||||||
|
const malformedSignature = {
|
||||||
|
v: signature.v,
|
||||||
|
r: malformedR,
|
||||||
|
s: signature.s,
|
||||||
|
};
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('s is not hex', () => {
|
||||||
|
const malformedS = signature.s.replace('0', 'z');
|
||||||
|
const malformedSignature = {
|
||||||
|
v: signature.v,
|
||||||
|
r: signature.r,
|
||||||
|
s: malformedS,
|
||||||
|
};
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, malformedSignature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should return false if the data doesn\'t pertain to the signature & address', () => {
|
||||||
|
const isValid = ZeroEx.isValidSignature('wrong data', signature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('should return false if the address doesn\'t pertain to the signature & data', () => {
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, signature, '0xIamWrong');
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('should return false if the signature doesn\'t pertain to the data & address', () => {
|
||||||
|
const wrongSignature = Object.assign({}, signature, {v: 28});
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, wrongSignature, address);
|
||||||
|
expect(isValid).to.be.false;
|
||||||
|
});
|
||||||
|
it('should return true if the signature does pertain to the data & address', () => {
|
||||||
|
const isValid = ZeroEx.isValidSignature(data, signature, address);
|
||||||
|
expect(isValid).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user