Skip to content

Commit bf2a92d

Browse files
author
Aleix Morgadas
authored
Merge pull request #10 from aizaiz/master
Added verifySignature function in PublicAccount class
2 parents 94bc0d6 + f1a4182 commit bf2a92d

File tree

2 files changed

+125
-5
lines changed

2 files changed

+125
-5
lines changed

src/model/account/PublicAccount.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {NetworkType} from '../blockchain/NetworkType';
18-
import {Address} from './Address';
17+
import { KeyPair, convert } from 'nem2-library';
18+
import { NetworkType } from '../blockchain/NetworkType';
19+
import { Address } from './Address';
1920

2021
/**
2122
* The public account structure contains account's address and public key.
@@ -53,6 +54,44 @@ export class PublicAccount {
5354
return new PublicAccount(publicKey, address);
5455
}
5556

57+
/**
58+
* Verify a signature.
59+
*
60+
* @param {PublicAccount} publicAccount - The public account to use for verification.
61+
* @param {string} data - The data to verify.
62+
* @param {string} signature - The signature to verify.
63+
*
64+
* @return {boolean} - True if the signature is valid, false otherwise.
65+
*/
66+
static verifySignature(publicAccount: PublicAccount, data: string, signature: string): boolean {
67+
if (!publicAccount || !data || !signature) {
68+
throw new Error('Missing argument');
69+
}
70+
71+
if (signature.length !== 128) {
72+
throw new Error('Signature length is incorrect');
73+
}
74+
75+
if (!convert.isHexString(signature)) {
76+
throw new Error('Signature must be hexadecimal only');
77+
}
78+
79+
// Convert signature key to Uint8Array
80+
const convertedSignature = convert.hexToUint8(signature);
81+
82+
let convertedData;
83+
84+
// Convert data to hex if data is not hex
85+
if (!convert.isHexString(data)) {
86+
convertedData = convert.utf8ToHex(data);
87+
}
88+
89+
// Convert to Uint8Array
90+
convertedData = convert.hexToUint8(convertedData);
91+
92+
return KeyPair.verify(publicAccount.publicKey, convertedData, convertedSignature);
93+
}
94+
5695
/**
5796
* Compares public accounts for equality.
5897
* @param publicAccount
@@ -61,4 +100,5 @@ export class PublicAccount {
61100
equals(publicAccount: PublicAccount) {
62101
return this.publicKey === publicAccount.publicKey && this.address.plain() === publicAccount.address.plain();
63102
}
103+
64104
}

test/model/account/PublicAccount.spec.ts

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import {expect} from 'chai';
18-
import {PublicAccount} from '../../../src/model/account/PublicAccount';
19-
import {NetworkType} from '../../../src/model/blockchain/NetworkType';
17+
import { expect } from 'chai';
18+
import { PublicAccount } from '../../../src/model/account/PublicAccount';
19+
import { NetworkType } from '../../../src/model/blockchain/NetworkType';
2020

2121
describe('PublicAccount', () => {
2222
const publicKey = 'b4f12e7c9f6946091e2cb8b6d3a12b50d17ccbbf646386ea27ce2946a7423dcf';
@@ -27,3 +27,83 @@ describe('PublicAccount', () => {
2727
expect(publicAccount.address.plain()).to.be.equal('SARNASAS2BIAB6LMFA3FPMGBPGIJGK6IJETM3ZSP');
2828
});
2929
});
30+
31+
describe('Signature verification', () => {
32+
it('Can verify a signature', () => {
33+
// Arrange:'
34+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
35+
NetworkType.MIJIN_TEST);
36+
const data = 'I am so so so awesome as always';
37+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F3526FA508'; // tslint:disable-line
38+
39+
// Act & Assert:
40+
expect(PublicAccount.verifySignature(signerPublicAccount, data, signature)).equal(true);
41+
});
42+
43+
it('Throw error if signature has invalid length', () => {
44+
// Arrange:
45+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
46+
NetworkType.MIJIN_TEST);
47+
const data = 'I am so so so awesome as always';
48+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C5486'; // tslint:disable-line
49+
50+
// Act & Assert:
51+
expect(() => { PublicAccount.verifySignature(signerPublicAccount, data, signature); }).to.throw('Signature length is incorrect');
52+
});
53+
54+
it('Throw error if signature is not strictly hexadecimal', () => {
55+
// Arrange:
56+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
57+
NetworkType.MIJIN_TEST);
58+
const data = 'I am so so so awesome as always';
59+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F35a1wwwww';// tslint:disable-line
60+
61+
// Act & Assert:
62+
expect(() => { PublicAccount.verifySignature(signerPublicAccount, data, signature); })
63+
.to.throw('Signature must be hexadecimal only');
64+
});
65+
66+
it('Return false if wrong public key provided', () => {
67+
// Arrange:
68+
const signerPublicAccount = PublicAccount.createFromPublicKey('12816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB509',
69+
NetworkType.MIJIN_TEST);
70+
const data = 'I am so so so awesome as always';
71+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F3526FA508';// tslint:disable-line
72+
73+
// Act & Assert:
74+
expect(PublicAccount.verifySignature(signerPublicAccount, data, signature)).equal(false);
75+
});
76+
77+
it('Return false if data is not corresponding to signature provided', () => {
78+
// Arrange:
79+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
80+
NetworkType.MIJIN_TEST);
81+
const data = 'I am awesome as always';
82+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F3526FA508';// tslint:disable-line
83+
84+
// Act & Assert:
85+
expect(PublicAccount.verifySignature(signerPublicAccount, data, signature)).equal(false);
86+
});
87+
88+
it('Return false if signature is not corresponding to data provided', () => {
89+
// Arrange:
90+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
91+
NetworkType.MIJIN_TEST);
92+
const data = 'I am so so so awesome as always';
93+
const signature = 'A01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F3526FA509';// tslint:disable-line
94+
95+
// Act & Assert:
96+
expect(PublicAccount.verifySignature(signerPublicAccount, data, signature)).equal(false);
97+
});
98+
99+
it('Throw error if signature verification is missing a parameter', () => {
100+
// Arrange:
101+
const signerPublicAccount = PublicAccount.createFromPublicKey('22816F825B4CACEA334723D51297D8582332D8B875A5829908AAE85831ABB508',
102+
NetworkType.MIJIN_TEST);
103+
const data = '';
104+
const signature = 'B01DCA6484026C2ECDF3C822E64DEAAFC15EBCCE337EEE209C28513CB5351CDED8863A8E7B855CD471B55C91FAE611C548625C9A5916A555A24F72F3526FA508';// tslint:disable-line
105+
106+
// Act & Assert:
107+
expect(() => { PublicAccount.verifySignature(signerPublicAccount, data, signature); }).to.throw('Missing argument');
108+
});
109+
});

0 commit comments

Comments
 (0)