Skip to content

Commit dd3a02a

Browse files
committed
JAV-18 [Github #253] Signature Schema Refactoring
1 parent 2601e19 commit dd3a02a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+451
-560
lines changed

src/core/crypto/Crypto.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { NetworkType } from '../../model/blockchain/NetworkType';
1718
import { WalletAlgorithm } from '../../model/wallet/WalletAlgorithm';
1819
import { Convert as convert } from '../format/Convert';
1920
import { KeyPair } from './KeyPair';
20-
import * as utility from './Utilities';
2121
import { SignSchema } from './SignSchema';
22+
import * as utility from './Utilities';
23+
// tslint:disable-next-line: no-var-requires
2224
const CryptoJS = require('crypto-js');
2325
export class Crypto {
2426
/**
@@ -219,16 +221,16 @@ export class Crypto {
219221
* @param {string} msg - A text message
220222
* @param {Uint8Array} iv - An initialization vector
221223
* @param {Uint8Array} salt - A salt
222-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
224+
* @param {NetworkType} networkType - Catapult network identifier
223225
* @return {string} - The encoded message
224226
*/
225-
public static _encode = (senderPriv, recipientPub, msg, iv, salt, signSchema: SignSchema = SignSchema.SHA3) => {
227+
public static _encode = (senderPriv, recipientPub, msg, iv, salt, networkType: NetworkType) => {
226228
// Errors
227229
if (!senderPriv || !recipientPub || !msg || !iv || !salt) { throw new Error('Missing argument !'); }
228230
// Processing
229-
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(senderPriv, signSchema);
231+
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(senderPriv, networkType);
230232
const pk = convert.hexToUint8(recipientPub);
231-
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, signSchema), 32);
233+
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, networkType), 32);
232234
const encIv = {
233235
iv: utility.ua2words(iv, 16),
234236
};
@@ -244,16 +246,16 @@ export class Crypto {
244246
* @param {string} senderPriv - A sender private key
245247
* @param {string} recipientPub - A recipient public key
246248
* @param {string} msg - A text message
247-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
249+
* @param {NetworkType} networkType - Catapult network identifier
248250
* @return {string} - The encoded message
249251
*/
250-
public static encode = (senderPriv, recipientPub, msg, signSchema: SignSchema = SignSchema.SHA3) => {
252+
public static encode = (senderPriv, recipientPub, msg, networkType: NetworkType) => {
251253
// Errors
252254
if (!senderPriv || !recipientPub || !msg) { throw new Error('Missing argument !'); }
253255
// Processing
254256
const iv = Crypto.randomBytes(16);
255257
const salt = Crypto.randomBytes(32);
256-
const encoded = Crypto._encode(senderPriv, recipientPub, msg, iv, salt, signSchema);
258+
const encoded = Crypto._encode(senderPriv, recipientPub, msg, iv, salt, networkType);
257259
// Result
258260
return encoded;
259261
}
@@ -264,16 +266,16 @@ export class Crypto {
264266
* @param {string} recipientPrivate - A recipient private key
265267
* @param {string} senderPublic - A sender public key
266268
* @param {Uint8Array} _payload - An encrypted message payload in bytes
267-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
269+
* @param {NetworkType} networkType - Catapult network identifier
268270
* @return {string} - The decoded payload as hex
269271
*/
270-
public static _decode = (recipientPrivate, senderPublic, payload, iv, salt, signSchema: SignSchema = SignSchema.SHA3) => {
272+
public static _decode = (recipientPrivate, senderPublic, payload, iv, salt, networkType: NetworkType) => {
271273
// Error
272274
if (!recipientPrivate || !senderPublic || !payload) { throw new Error('Missing argument !'); }
273275
// Processing
274-
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(recipientPrivate, signSchema);
276+
const keyPair = KeyPair.createKeyPairFromPrivateKeyString(recipientPrivate, networkType);
275277
const pk = convert.hexToUint8(senderPublic);
276-
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, signSchema), 32);
278+
const encKey = utility.ua2words(KeyPair.deriveSharedKey(keyPair, pk, salt, networkType), 32);
277279
const encIv = {
278280
iv: utility.ua2words(iv, 16),
279281
};
@@ -291,18 +293,18 @@ export class Crypto {
291293
* @param {string} recipientPrivate - A recipient private key
292294
* @param {string} senderPublic - A sender public key
293295
* @param {string} _payload - An encrypted message payload
294-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
296+
* @param {NetworkType} networkType - Catapult network identifier
295297
* @return {string} - The decoded payload as hex
296298
*/
297-
public static decode = (recipientPrivate, senderPublic, _payload, signSchema: SignSchema = SignSchema.SHA3) => {
299+
public static decode = (recipientPrivate, senderPublic, _payload, networkType: NetworkType) => {
298300
// Error
299301
if (!recipientPrivate || !senderPublic || !_payload) { throw new Error('Missing argument !'); }
300302
// Processing
301303
const binPayload = convert.hexToUint8(_payload);
302304
const payload = new Uint8Array(binPayload.buffer, 48);
303305
const salt = new Uint8Array(binPayload.buffer, 0, 32);
304306
const iv = new Uint8Array(binPayload.buffer, 32, 16);
305-
const decoded = Crypto._decode(recipientPrivate, senderPublic, payload, iv, salt, signSchema);
307+
const decoded = Crypto._decode(recipientPrivate, senderPublic, payload, iv, salt, networkType);
306308
return decoded;
307309
}
308310

@@ -316,4 +318,18 @@ export class Crypto {
316318
const crypto = require('crypto');
317319
return crypto.randomBytes(length);
318320
}
321+
322+
/**
323+
* Resolve signature schema from given network type
324+
*
325+
* @param {NetworkType} networkType - Network type
326+
*
327+
* @return {SignSchema}
328+
*/
329+
public static resolveNetworkType(networkType: NetworkType): SignSchema {
330+
if (networkType === NetworkType.MAIN_NET || networkType === NetworkType.TEST_NET) {
331+
return SignSchema.KECCAK;
332+
}
333+
return SignSchema.SHA3;
334+
}
319335
}

src/core/crypto/KeyPair.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,23 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
import { NetworkType } from '../../model/blockchain/NetworkType';
1617
import { Convert as convert } from '../format';
17-
import { SignSchema } from './SignSchema';
1818
import * as Utility from './Utilities';
1919

2020
export class KeyPair {
2121
/**
2222
* Creates a key pair from a private key string.
2323
* @param {string} privateKeyString A hex encoded private key string.
24-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
24+
* @param {networkType} networkType Catapult network identifier
2525
* @returns {module:crypto/keyPair~KeyPair} The key pair.
2626
*/
27-
public static createKeyPairFromPrivateKeyString = (privateKeyString, signSchema = SignSchema.SHA3) => {
27+
public static createKeyPairFromPrivateKeyString = (privateKeyString: string, networkType: NetworkType) => {
2828
const privateKey = convert.hexToUint8(privateKeyString);
29-
30-
// KECCAK_REVERSED_KEY uses reversed private key.
31-
const secretKey = signSchema === SignSchema.SHA3 ? privateKey : convert.hexToUint8Reverse(privateKeyString);
3229
if (Utility.Key_Size !== privateKey.length) {
3330
throw Error(`private key has unexpected size: ${privateKey.length}`);
3431
}
35-
const publicKey = Utility.catapult_crypto.extractPublicKey(secretKey, Utility.catapult_hash.func, signSchema);
32+
const publicKey = Utility.catapult_crypto.extractPublicKey(privateKey, Utility.catapult_hash.func, networkType);
3633
return {
3734
privateKey,
3835
publicKey,
@@ -43,29 +40,24 @@ export class KeyPair {
4340
* Signs a data buffer with a key pair.
4441
* @param {module:crypto/keyPair~KeyPair} keyPair The key pair to use for signing.
4542
* @param {Uint8Array} data The data to sign.
46-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
43+
* @param {networkType} networkType Catapult network identifier
4744
* @returns {Uint8Array} The signature.
4845
*/
49-
public static sign = (keyPair, data, signSchema = SignSchema.SHA3) => {
50-
let secretKey = keyPair.privateKey;
51-
// KECCAK_REVERSED_KEY uses reversed private key.
52-
if (signSchema === SignSchema.KECCAK_REVERSED_KEY) {
53-
secretKey = convert.hexToUint8Reverse(convert.uint8ToHex(secretKey));
54-
}
55-
return Utility.catapult_crypto.sign(data, keyPair.publicKey, secretKey,
56-
Utility.catapult_hash.createHasher(64, signSchema));
46+
public static sign = (keyPair, data: Uint8Array, networkType: NetworkType) => {
47+
return Utility.catapult_crypto.sign(data, keyPair.publicKey, keyPair.privateKey,
48+
Utility.catapult_hash.createHasher(64, networkType));
5749
}
5850

5951
/**
6052
* Verifies a signature.
6153
* @param {module:crypto/keyPair~PublicKey} publicKey The public key to use for verification.
6254
* @param {Uint8Array} data The data to verify.
6355
* @param {Uint8Array} signature The signature to verify.
64-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
56+
* @param {networkType} networkType Catapult network identifier
6557
* @returns {boolean} true if the signature is verifiable, false otherwise.
6658
*/
67-
public static verify = (publicKey, data, signature, signSchema = SignSchema.SHA3) => {
68-
return Utility.catapult_crypto.verify(publicKey, data, signature, Utility.catapult_hash.createHasher(64, signSchema));
59+
public static verify = (publicKey, data: Uint8Array, signature: Uint8Array, networkType: NetworkType) => {
60+
return Utility.catapult_crypto.verify(publicKey, data, signature, Utility.catapult_hash.createHasher(64, networkType));
6961
}
7062

7163
/**
@@ -74,21 +66,16 @@ export class KeyPair {
7466
* @param {module:crypto/keyPair~KeyPair} keyPair The key pair for which to create the shared key.
7567
* @param {Uint8Array} publicKey The public key for which to create the shared key.
7668
* @param {Uint8Array} salt A salt that should be applied to the shared key.
77-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
69+
* @param {networkType} networkType Catapult network identifier
7870
* @returns {Uint8Array} The shared key.
7971
*/
80-
public static deriveSharedKey = (keyPair, publicKey, salt, signSchema = SignSchema.SHA3) => {
72+
public static deriveSharedKey = (keyPair, publicKey: Uint8Array, salt: Uint8Array, networkType: NetworkType) => {
8173
if (Utility.Key_Size !== salt.length) {
8274
throw Error(`salt has unexpected size: ${salt.length}`);
8375
}
8476
if (Utility.Key_Size !== publicKey.length) {
8577
throw Error(`public key has unexpected size: ${salt.length}`);
8678
}
87-
let secretKey = keyPair.privateKey;
88-
// KECCAK_REVERSED_KEY uses reversed private key.
89-
if (signSchema === SignSchema.KECCAK_REVERSED_KEY) {
90-
secretKey = convert.hexToUint8Reverse(convert.uint8ToHex(secretKey));
91-
}
92-
return Utility.catapult_crypto.deriveSharedKey(salt, secretKey, publicKey, Utility.catapult_hash.func, signSchema);
79+
return Utility.catapult_crypto.deriveSharedKey(salt, keyPair.privateKey, publicKey, Utility.catapult_hash.func, networkType);
9380
}
9481
}

src/core/crypto/SHA3Hasher.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616

1717
import { keccak256, keccak512, sha3_256, sha3_512 } from 'js-sha3';
18+
import { NetworkType } from '../../model/blockchain/NetworkType';
1819
import { Convert as convert, RawArray as array } from '../format';
20+
import { Crypto } from './Crypto';
1921
import { SignSchema } from './SignSchema';
2022

2123
export class SHA3Hasher {
@@ -24,25 +26,25 @@ export class SHA3Hasher {
2426
* @param {Uint8Array} dest The computed hash destination.
2527
* @param {Uint8Array} data The data to hash.
2628
* @param {numeric} length The hash length in bytes.
27-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
29+
* @param {NetworkType} networkType Catapult network identifier
2830
*/
29-
public static func = (dest, data, length, signSchema = SignSchema.SHA3) => {
30-
const hasher = SHA3Hasher.getHasher(length, signSchema);
31+
public static func = (dest, data, length, networkType: NetworkType) => {
32+
const hasher = SHA3Hasher.getHasher(length, networkType);
3133
const hash = hasher.arrayBuffer(data);
3234
array.copy(dest, array.uint8View(hash));
3335
}
3436

3537
/**
3638
* Creates a hasher object.
3739
* @param {numeric} length The hash length in bytes.
38-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
40+
* @param {NetworkType} networkType Catapult network identifier
3941
* @returns {object} The hasher.
4042
*/
41-
public static createHasher = (length = 64, signSchema = SignSchema.SHA3) => {
43+
public static createHasher = (length = 64, networkType: NetworkType) => {
4244
let hash;
4345
return {
4446
reset: () => {
45-
hash = SHA3Hasher.getHasher(length, signSchema).create();
47+
hash = SHA3Hasher.getHasher(length, networkType).create();
4648
},
4749
update: (data: any) => {
4850
if (data instanceof Uint8Array) {
@@ -62,13 +64,25 @@ export class SHA3Hasher {
6264
/**
6365
* Get a hasher instance.
6466
* @param {numeric} length The hash length in bytes.
65-
* @param {SignSchema} signSchema The Sign Schema. (KECCAK_REVERSED_KEY / SHA3)
67+
* @param {NetworkType} networkType Catapult network identifier
6668
* @returns {object} The hasher.
6769
*/
68-
public static getHasher = (length = 64, signSchema = SignSchema.SHA3) => {
70+
public static getHasher = (length = 64, networkType: NetworkType) => {
71+
const signSchema = Crypto.resolveNetworkType(networkType);
6972
return {
7073
32: signSchema === SignSchema.SHA3 ? sha3_256 : keccak256,
7174
64: signSchema === SignSchema.SHA3 ? sha3_512 : keccak512 ,
7275
} [length];
7376
}
77+
78+
/**
79+
* Create a hasher instance with given payload bytes and return hash array buffer.
80+
* @param {Uint8Array} payload Payload in bytes.
81+
* @param {NetworkType} networkType Catapult network identifier
82+
* @returns {ArrayBuffer}
83+
*/
84+
public static getHashArrayBuffer(payload: Uint8Array, networkType: NetworkType): ArrayBuffer {
85+
const signSchema = Crypto.resolveNetworkType(networkType);
86+
return signSchema === SignSchema.SHA3 ? sha3_256.arrayBuffer(payload) : keccak256.arrayBuffer(payload);
87+
}
7488
}

src/core/crypto/SignSchema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
*/
1616

1717
/**
18-
* [KECCAK_REVERSED_KEY]: Keccak hash algorithm with reversed private keys.
18+
* [KECCAK]: Keccak hash algorithm.
1919
* [SHA3]: SHA3 hash algorithm without key reversal
2020
*/
2121
export enum SignSchema {
22-
KECCAK_REVERSED_KEY = 1,
22+
KECCAK = 1,
2323
SHA3 = 2,
2424
}

src/core/crypto/Utilities.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
import { NetworkType } from '../../model/blockchain/NetworkType';
1617
import { RawArray as array } from '../format';
1718
import * as nacl from './nacl_catapult';
1819
import { SHA3Hasher as sha3Hasher } from './SHA3Hasher';
19-
import { SignSchema } from './SignSchema';
2020
export const CryptoJS = require('crypto-js');
2121
export const Key_Size = 32;
2222
export const Signature_Size = 64;
@@ -74,9 +74,9 @@ export const catapult_crypto = (function() {
7474
d[31] |= 64;
7575
}
7676

77-
function prepareForScalarMult(sk, hashfunc, signSchema: SignSchema) {
77+
function prepareForScalarMult(sk, hashfunc, networkType: NetworkType) {
7878
const d = new Uint8Array(Hash_Size);
79-
hashfunc(d, sk, Hash_Size, signSchema);
79+
hashfunc(d, sk, Hash_Size, networkType);
8080
clamp(d);
8181
return d;
8282
}
@@ -108,9 +108,9 @@ export const catapult_crypto = (function() {
108108
})();
109109

110110
return {
111-
extractPublicKey: (sk, hashfunc, signSchema: SignSchema) => {
111+
extractPublicKey: (sk, hashfunc, networkType: NetworkType) => {
112112
const c = nacl;
113-
const d = prepareForScalarMult(sk, hashfunc, signSchema);
113+
const d = prepareForScalarMult(sk, hashfunc, networkType);
114114

115115
const p = [c.gf(), c.gf(), c.gf(), c.gf()];
116116
const pk = new Uint8Array(Key_Size);
@@ -201,9 +201,9 @@ export const catapult_crypto = (function() {
201201
return 0 === c.crypto_verify_32(signature, 0, t, 0);
202202
},
203203

204-
deriveSharedKey: (salt, sk, pk, hashfunc, signSchema: SignSchema) => {
204+
deriveSharedKey: (salt, sk, pk, hashfunc, networkType: NetworkType) => {
205205
const c = nacl;
206-
const d = prepareForScalarMult(sk, hashfunc, signSchema);
206+
const d = prepareForScalarMult(sk, hashfunc, networkType);
207207

208208
// sharedKey = pack(p = d (derived from sk) * q (derived from pk))
209209
const q = [c.gf(), c.gf(), c.gf(), c.gf()];
@@ -218,7 +218,7 @@ export const catapult_crypto = (function() {
218218
}
219219
// return the hash of the result
220220
const sharedKeyHash = new Uint8Array(Key_Size);
221-
hashfunc(sharedKeyHash, sharedKey, Key_Size, signSchema);
221+
hashfunc(sharedKeyHash, sharedKey, Key_Size, networkType);
222222
return sharedKeyHash;
223223
},
224224
};

src/core/crypto/nacl_catapult.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -672,11 +672,11 @@ export const cleanup = (arr) => {
672672
}
673673
};
674674

675-
export const crypto_shared_key_hash = (shared, pk, sk, hashfunc, signSchema) => {
675+
export const crypto_shared_key_hash = (shared, pk, sk, hashfunc, networkType) => {
676676
const d = new Uint8Array(64);
677677
const p = [gf(), gf(), gf(), gf()];
678678

679-
hashfunc(d, sk, 32, signSchema);
679+
hashfunc(d, sk, 32, networkType);
680680
d[0] &= 248;
681681
d[31] &= 127;
682682
d[31] |= 64;

0 commit comments

Comments
 (0)