commit a44709b5372375d18a77524d3779f739ef59efd7
parent 84d677e19f28f50100e7712fe4bcaeaa1b38967e
Author: finwo <finwo@pm.me>
Date: Wed, 19 Jun 2019 12:30:26 +0200
Helper functions are now tested as well
Diffstat:
| M | index.js | | | 62 | +++++++++++++++++++++++++++++++++++++++++++++++--------------- |
| M | test.js | | | 130 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
2 files changed, 146 insertions(+), 46 deletions(-)
diff --git a/index.js b/index.js
@@ -5,14 +5,48 @@ function randomBytes(length) {
return Buffer.from(new Array(length).fill(0).map(()=>Math.floor(Math.random()*256)));
}
+function checkArguments( namedArguments, callback ) {
+ callback = callback || function( err ) {
+ if (!err) return;
+ if (err instanceof Error) throw err;
+ throw new Error(err);
+ };
+
+ if ('object' !== typeof namedArguments) return callback('Expected object, ' + (typeof namedArguments) + ' given');
+ if (!namedArguments) return callback('Expected object, null given');
+ if ( 'seed' in namedArguments ) {
+ if (!isBuffer(namedArguments.seed) ) return callback('Seed is not a buffer');
+ if (namedArguments.seed.length !== 32) return callback('Seed must be 32 bytes');
+ }
+ if ( 'signature' in namedArguments ) {
+ if (!isBuffer(namedArguments.signature)) return callback('Signature is not a buffer');
+ if (namedArguments.signature.length !== 64) return callback('Signature must be 64 bytes');
+ }
+ if ( 'message' in namedArguments ) {
+ if (!isBuffer(namedArguments.message)) return callback('Message is not a buffer');
+ }
+ if ( 'publicKey' in namedArguments ) {
+ if (!isBuffer(namedArguments.publicKey) ) return callback('Public key is not a buffer');
+ if (namedArguments.publicKey.length !== 32) return callback('Public key must be 32 bytes');
+ }
+ if ( 'secretKey' in namedArguments ) {
+ if (!isBuffer(namedArguments.secretKey) ) return callback('Secret key is not a buffer');
+ if (namedArguments.secretKey.length !== 64) return callback('Secret key must be 64 bytes');
+ }
+
+ return callback();
+}
+
+// Export helpers
+exports._checkArguments = checkArguments;
+exports._randomBytes = randomBytes;
+
exports.createSeed = function(){
return randomBytes(32);
};
exports.createKeyPair = function(seed) {
- if(!Buffer.isBuffer(seed)){
- throw new Error('not buffers!');
- }
+ checkArguments({seed});
var seedPtr = Module._malloc(32);
var seedBuf = new Uint8Array(Module.HEAPU8.buffer, seedPtr, 32);
var publicKeyPtr = Module._malloc(32);
@@ -31,9 +65,8 @@ exports.createKeyPair = function(seed) {
};
exports.sign = function(message, publicKey, secretKey){
- if(!Buffer.isBuffer(message) || !Buffer.isBuffer(publicKey) || !Buffer.isBuffer(secretKey)){
- throw new Error('not buffers!');
- }
+ if ('string' === typeof message) message = Buffer.from(message);
+ checkArguments({message,publicKey,secretKey});
var messageLen = message.length;
var messageArrPtr = Module._malloc(messageLen);
var messageArr = new Uint8Array(Module.HEAPU8.buffer, messageArrPtr, messageLen);
@@ -54,23 +87,22 @@ exports.sign = function(message, publicKey, secretKey){
return new Buffer(sig);
};
-exports.verify = function(sig, message, publicKey){
- if(!Buffer.isBuffer(message) || !Buffer.isBuffer(sig) || !Buffer.isBuffer(publicKey)){
- throw new Error('not buffers!');
- }
+exports.verify = function(signature, message, publicKey){
+ if ('string' === typeof message) message = Buffer.from(message);
+ checkArguments({signature,message,publicKey});
var messageLen = message.length;
var messageArrPtr = Module._malloc(messageLen);
var messageArr = new Uint8Array(Module.HEAPU8.buffer, messageArrPtr, messageLen);
- var sigArrPtr = Module._malloc(64);
- var sigArr = new Uint8Array(Module.HEAPU8.buffer, sigArrPtr, 64);
+ var signatureArrPtr = Module._malloc(64);
+ var signatureArr = new Uint8Array(Module.HEAPU8.buffer, signatureArrPtr, 64);
var publicKeyArrPtr = Module._malloc(32);
var publicKeyArr = new Uint8Array(Module.HEAPU8.buffer, publicKeyArrPtr, 32);
messageArr.set(message);
- sigArr.set(sig);
+ signatureArr.set(signature);
publicKeyArr.set(publicKey);
- var res = Module._verify(sigArrPtr, messageArrPtr, messageLen, publicKeyArrPtr) === 1;
+ var res = Module._verify(signatureArrPtr, messageArrPtr, messageLen, publicKeyArrPtr) === 1;
Module._free(messageArrPtr);
- Module._free(sigArrPtr);
+ Module._free(signatureArrPtr);
Module._free(publicKeyArrPtr);
return res;
};
diff --git a/test.js b/test.js
@@ -1,41 +1,109 @@
-var test = require('tape');
-var lib = require('./index.js');
-var crypto = require('crypto');
+const isBuffer = require('is-buffer');
+const test = require('tape');
+const lib = require('./index.js');
-test('key generation', function(t){
+test('Type checks', t => {
+ t.plan(7);
+ t.is((!!lib) && (typeof lib) , 'object' , 'supercop is an object' );
+ t.is(typeof lib._randomBytes , 'function', 'export helper: _randomBytes' );
+ t.is(typeof lib._checkArguments, 'function', 'export helper: _checkArguments');
+ t.is(typeof lib.createSeed , 'function', 'export method: createSeed' );
+ t.is(typeof lib.createKeyPair , 'function', 'export method: createKeyPair' );
+ t.is(typeof lib.sign , 'function', 'export method: sign' );
+ t.is(typeof lib.verify , 'function', 'export method: verify' );
+});
+
+test('Random bytes generation', t => {
+ t.plan(4);
+
+ const randomBytes32 = lib._randomBytes(32);
+ const randomBytes64 = lib._randomBytes(64);
+
+ t.is(isBuffer(randomBytes32), true, 'Random32 is a buffer');
+ t.is(isBuffer(randomBytes64), true, 'Random64 is a buffer');
+ t.is(randomBytes32.length , 32 , 'Random32 is 32 bytes long');
+ t.is(randomBytes64.length , 64 , 'Random64 is 64 bytes long');
+});
+
+test('Argument validation', t => {
+ t.plan(14);
+
+ // We'll not throw in this test
+ const callback = function(err) {
+ if (!err) return false;
+ if (err instanceof Error) return err.message;
+ return err;
+ };
+
+ // Variables to test with
+ const undef = undefined;
+ const rightSeed = lib._randomBytes(32);
+ const wrongSeed = lib._randomBytes(33);
+ const rightPublicKey = lib._randomBytes(32);
+ const wrongPublicKey = lib._randomBytes(33);
+ const rightSecretKey = lib._randomBytes(64);
+ const wrongSecretKey = lib._randomBytes(65);
+ const randomMessage = lib._randomBytes(1024);
+
+ t.is(lib._checkArguments(null , callback), 'Expected object, null given' , 'Failure on null argument');
+ t.is(lib._checkArguments('some string' , callback), 'Expected object, string given' , 'Failure on string argument');
+ t.is(lib._checkArguments(callback , callback), 'Expected object, function given', 'Failure on function argument');
+ t.is(lib._checkArguments({ seed : undef }, callback), 'Seed is not a buffer' , 'Failure on undefined seed');
+ t.is(lib._checkArguments({ seed : rightSeed }, callback), false , 'Success on 32-byte seed');
+ t.is(lib._checkArguments({ seed : wrongSeed }, callback), 'Seed must be 32 bytes' , 'Failure on 33-byte seed');
+ t.is(lib._checkArguments({ publicKey: undef }, callback), 'Public key is not a buffer' , 'Failure on undefined public key');
+ t.is(lib._checkArguments({ publicKey: rightPublicKey }, callback), false , 'Success on 32-byte public key');
+ t.is(lib._checkArguments({ publicKey: wrongPublicKey }, callback), 'Public key must be 32 bytes' , 'Failure on 33-byte public key');
+ t.is(lib._checkArguments({ secretKey: undef }, callback), 'Secret key is not a buffer' , 'Failure on undefined secret key');
+ t.is(lib._checkArguments({ secretKey: rightSecretKey }, callback), false , 'Success on 64-byte secret key');
+ t.is(lib._checkArguments({ secretKey: wrongSecretKey }, callback), 'Secret key must be 64 bytes' , 'Failure on 65-byte secret key');
+ t.is(lib._checkArguments({ message : undef }, callback), 'Message is not a buffer' , 'Failure on undefined message');
+ t.is(lib._checkArguments({ message : randomMessage }, callback), false , 'Success on buffer message');
+});
+
+test('Key generation', t => {
t.plan(6);
- var seed = lib.createSeed();
- t.is(Buffer.isBuffer(seed), true, 'seed is a buffer');
- t.is(seed.length, 32, 'seed\'s length is 32');
- var keys = lib.createKeyPair(seed);
- t.is(Buffer.isBuffer(keys.publicKey), true, 'pub key is a buffer');
- t.is(keys.publicKey.length, 32, 'pub key\'s length is 32');
- t.is(Buffer.isBuffer(keys.secretKey), true, 'priv key is a buffer');
- t.is(keys.secretKey.length, 64, 'priv key\'s length is 64');
+ const seed = lib.createSeed();
+ t.is(isBuffer(seed), true, 'Seed is a buffer' );
+ t.is(seed.length , 32 , 'Seed\'s length is 32');
+
+ const keys = lib.createKeyPair(seed);
+ t.is(isBuffer(keys.publicKey), true, 'Public key is a buffer' );
+ t.is(keys.publicKey.length , 32 , 'Public key\'s length is 32');
+ t.is(isBuffer(keys.secretKey), true, 'Secret key is a buffer' );
+ t.is(keys.secretKey.length , 64 , 'Secret key\'s length is 64');
});
-test('signatures', function(t){
+test('Signatures', t => {
t.plan(2);
- var seed = lib.createSeed();
- var keys = lib.createKeyPair(seed);
- var sig = lib.sign(new Buffer('hello there m8'), keys.publicKey, keys.secretKey);
- t.is(Buffer.isBuffer(sig), true, 'is signature buffer');
- t.is(sig.length, 64, 'is signature\'s length 64');
+ const seed = lib.createSeed();
+ const keys = lib.createKeyPair(seed);
+ const signature = lib.sign(new Buffer('hello there m8'), keys.publicKey, keys.secretKey);
+
+ t.is(isBuffer(signature), true, 'Signature is a buffer');
+ t.is(signature.length , 64 , 'Signature\'s length is 64 bytes');
});
-test('verify', function(t){
- t.plan(3);
-
- var seed = lib.createSeed();
- var keys = lib.createKeyPair(seed);
- var msg = new Buffer('hello there m8');
- var wrongMsg = crypto.randomBytes(msg.length);
- var sig = lib.sign(msg, keys.publicKey, keys.secretKey);
- var wrongSeed = lib.createSeed();
- var wrongKeys = lib.createKeyPair(wrongSeed);
- t.is(lib.verify(sig, msg, keys.publicKey), true, 'right stuff verifies correctly');
- t.is(lib.verify(sig, wrongMsg, keys.publicKey), false, 'wrong message is incorrect');
- t.is(lib.verify(sig, msg, wrongKeys.publicKey), false, 'wrong key is incorrect');
+test('Verify', t => {
+ t.plan(4);
+
+ const seed = lib.createSeed();
+ const keys = lib.createKeyPair(seed);
+ const messageBuf = new Buffer('hello there m8');
+ const messageStr = 'hello there m8';
+ const wrongMessage = lib._randomBytes(messageBuf.length);
+
+ const signatureBuf = lib.sign(messageBuf, keys.publicKey, keys.secretKey);
+ const signatureStr = lib.sign(messageStr, keys.publicKey, keys.secretKey);
+
+ t.is(Buffer.compare(signatureBuf, signatureStr), 0, 'String and buffer sourced signature match');
+
+ const wrongSeed = lib.createSeed();
+ const wrongKeys = lib.createKeyPair(wrongSeed);
+
+ t.is(lib.verify(signatureBuf, messageBuf, keys.publicKey) , true , 'Signature verified message');
+ t.is(lib.verify(signatureBuf, wrongMessage, keys.publicKey) , false, 'Different messaged does not verify');
+ t.is(lib.verify(signatureBuf, messageBuf, wrongKeys.publicKey), false, 'Different public key does not verify');
});