Skip to content

Commit

Permalink
Merge pull request #12 from ceejbot/ceej/all-streaming-algos
Browse files Browse the repository at this point in the history
Expose all of the algorithms to the streaming API.
  • Loading branch information
ceejbot committed Mar 6, 2016
2 parents daff6bf + ddf395a commit 9e33bb4
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 117 deletions.
65 changes: 25 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# avon

Node bindings for the [blake2](https://blake2.net) cryptographic hash function.
Node bindings for the [blake2](https://blake2.net) cryptographic hash function. The relationship of Avon to Blake is of course [obvious](https://en.wikipedia.org/wiki/Kerr_Avon).

Blake2 provides four different hashing functions:

Expand All @@ -15,15 +15,17 @@ Tested on node 0.10, 4.x, and 5.x.

## Usage

All four functions take an optional callback. If no callback is provided, they return promises. Use the control flow method you prefer! The calculated hash is a node Buffer.
Avon exports `sumFile()`, `sumBuffer()`, and `sumStream()` functions to calculate a hash for whatever sort of data you have. All three functions take an optional callback. If no callback is provided, they return promises. Use the control flow method you prefer! The calculated hash is a node Buffer.

If you don't specify an algorithm, the 64-bit single-core `B` algorithm is used.

```javascript
var Avon = require('avon');
var assert = require('assert');

var buf = new Buffer('this is some input');

Avon.sumBuffer(buf)
Avon.sumBuffer(buf, Avon.ALGORITHMS.BP)
.then(function(hash)
{
assert(hash instanceof Buffer);
Expand All @@ -37,38 +39,24 @@ Avon.sumBuffer(buf, function(err, buffer)
{
if (err) console.error('noooo!');
else console.log(buffer.toString('hex'))
})
});
```

There are variations that take a filename as input:

```javascript
Avon.sumFile('my_file.dat')
.then(function(hash)
{
assert(hash instanceof Buffer);
console.log(hash.toString('hex'));
}, function(err)
{
console.error('noooooo! ' + err.message);
}).done();

Avon.sumFile('my_file.dat', function(err, buffer)
Avon.sumFile('my_file.dat', , Avon.ALGORITHMS.SP, function(err, buffer)
{
if (err) console.error('noooo!');
else console.log(buffer.toString('hex'))
})
});
```

## Streams!

The blake2 64-bit single core (aka blake2 b) algorithm is exposed with a streaming interface.
Or create a stream:

```js
var Avon = require('avon');

var input = fs.createReadStream('my-large-file');
var hasher = Avon.sumStream();
var hasher = Avon.sumStream(Avon.ALGORITHMS.BP);

input.on('close', function()
{
Expand All @@ -82,26 +70,23 @@ input.pipe(hasher);

## API

The following function are exported. This chart might help you decide which to use.
`Avon.ALGORITHMS` exports the enum-like list of algorithms: `B`, `BP`, `S`, and `SP`.

Blake2 provides a bewildering variety of variations. Avon exposes all of them. This chart might help you decide which to use.

| function | input | arch | multicore? | blake name
| function | input | arch | multicore? | algo name
| --- | --- | --- | --- | ---
| sumStream | stream | 64 | n | blake 2b
| sumBuffer | buffer | 64 | n | alias for blake2()
| sumFile | file | 64 | n | alias for blake2File()
| blake2 | buffer | 64 | n | 2b
| blake2SMP | buffer | 64 | y | 2bp
| blake2_32 | buffer | 32 | n | 2s
| blake2_32SMP | buffer | 32 | y | 2sp
| blake2File | file | 64 | n | 2b
| blake2SMPFile | file | 64 | y | 2bp
| blake2_32File | file | 32 | n | 2s
| blake2_32SMPFile | file | 32 | y | 2sp


## TODO

- Provide the other algorithms in streaming form.
| sumStream | stream | * | * | pass algo name
| sumBuffer | buffer | * | * | pass algo name
| sumFile | file | * | * | pass algo name
| blake2 | buffer | 64 | n | B
| blake2SMP | buffer | 64 | y | BP
| blake2_32 | buffer | 32 | n | S
| blake2_32SMP | buffer | 32 | y | SP
| blake2File | file | 64 | n | B
| blake2SMPFile | file | 64 | y | BP
| blake2_32File | file | 32 | n | S
| blake2_32SMPFile | file | 32 | y | SP

## Notes

Expand Down
32 changes: 26 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,35 @@ function wrapperFile(algo, fname)
return deferred.promise;
}

// blake2bp - multicore, 64
function sumBuffer(buffer, algorithm, callback)
{
if (typeof algorithm === 'function')
{
callback = algorithm;
algorithm = B;
}
return wrapper(algorithm, buffer).nodeify(callback);
}

function sumFile(fname, algorithm, callback)
{
if (typeof algorithm === 'function')
{
callback = algorithm;
algorithm = B;
}
return wrapperFile(algorithm, fname).nodeify(callback);
}

module.exports =
{
// convenience wrappers
sumBuffer: sumBuffer,
sumFile: sumFile,
sumStream: require('./streaming'),
ALGORITHMS: require('./streaming').ALGORITHMS,

// exposing the implementations
blake2: function(buffer, callback) { return wrapper(B, buffer).nodeify(callback); },
blake2SMP: function(buffer, callback) { return wrapper(BP, buffer).nodeify(callback); },
blake2_32: function(buffer, callback) { return wrapper(S, buffer).nodeify(callback); },
Expand All @@ -50,9 +75,4 @@ module.exports =
blake2SMPFile: function(fname, callback) { return wrapperFile(BP, fname).nodeify(callback); },
blake2_32File: function(fname, callback) { return wrapperFile(S, fname).nodeify(callback); },
blake2_32SMPFile: function(fname, callback) { return wrapperFile(SP, fname).nodeify(callback); },
sumStream: require('./streaming')
};

// Aliases for the most common.
module.exports.sumBuffer = module.exports.blake2;
module.exports.sumFile = module.exports.blake2File;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "avon",
"description": "node bindings for the blake2 cryptographic hash",
"version": "0.3.0",
"version": "1.0.0",
"author": "C J Silverio <ceejceej@gmail.com>",
"bugs": {
"url": "https://github.com/ceejbot/avon/issues"
Expand Down
2 changes: 1 addition & 1 deletion src/avon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ NAN_MODULE_INIT(InitAll)
Nan::New<String>("b2_buffer").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(HashBuffer)).ToLocalChecked()
);
Streamer::Initialize(target);
AvonStream::Initialize(target);
}

NODE_MODULE(blake2, InitAll)
144 changes: 109 additions & 35 deletions src/streamer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,12 @@
using namespace v8;
using namespace node;

Streamer::Streamer(int algo)
{
mLength = BLAKE2B_OUTBYTES;
blake2b_init(state, mLength);
}

Streamer::~Streamer() {}

NAN_MODULE_INIT(Streamer::Initialize)
{
v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);

t->SetClassName(Nan::New<String>("Streamer").ToLocalChecked());
t->InstanceTemplate()->SetInternalFieldCount(2);

Nan::SetPrototypeMethod(t, "update", UpdateB);
Nan::SetPrototypeMethod(t, "final", FinalB);

constructor().Reset(Nan::GetFunction(t).ToLocalChecked());
Nan::Set(target, Nan::New("Streamer").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked());
}

NAN_METHOD(Streamer::New)
NAN_METHOD(AvonStream::New)
{
if (info.IsConstructCall())
{
int algo = info[0]->IsUndefined() ? 0 : Nan::To<int>(info[0]).FromJust();
Streamer* obj = new Streamer(algo);
AvonStream* obj = new AvonStream(algo);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
Expand All @@ -53,28 +31,124 @@ NAN_METHOD(Streamer::New)
}
}

NAN_METHOD(Streamer::UpdateB)
AvonStream::AvonStream(int algorithm)
{
Streamer* hash = ObjectWrap::Unwrap<Streamer>(info.Holder());
switch (algorithm)
{
case B:
default:
mHash = new Blake2B();
break;

case BP:
mHash = new Blake2BP();
break;

case S:
mHash = new Blake2S();
break;

case SP:
mHash = new Blake2SP();
break;
}
}

AvonStream::~AvonStream()
{
delete mHash;
}

NAN_METHOD(AvonStream::Update)
{
AvonStream* obj = ObjectWrap::Unwrap<AvonStream>(info.Holder());
Local<Object> buffer = info[0].As<Object>();
size_t length = node::Buffer::Length(buffer);
char* data = node::Buffer::Data(buffer);
hash->Update(data, length);
obj->mHash->Update(data, length);
}

NAN_METHOD(AvonStream::Final)
{
AvonStream* obj = ObjectWrap::Unwrap<AvonStream>(info.Holder());
obj->mHash->Final();
info.GetReturnValue().Set(Nan::CopyBuffer((const char *)obj->mHash->mResult, obj->mHash->mLength).ToLocalChecked());
}

// --- blake2 algorithms

Blake2B::Blake2B():Blake2Algorithm(BLAKE2B_OUTBYTES)
{
blake2b_init(mState, mLength);
}

NAN_METHOD(Streamer::FinalB)
void Blake2B::Update(const void *buffer, size_t length)
{
Streamer* hash = ObjectWrap::Unwrap<Streamer>(info.Holder());
hash->Final();
info.GetReturnValue().Set(Nan::CopyBuffer((const char *)hash->mResult, hash->mLength).ToLocalChecked());
blake2b_update(mState, (unsigned char *)buffer, length);
}

void Streamer::Update(const void *buffer, size_t length)
void Blake2B::Final()
{
blake2b_update(state, (unsigned char *)buffer, length);
blake2b_final(mState, mResult, mLength);
}

void Streamer::Final()
Blake2BP::Blake2BP():Blake2Algorithm(BLAKE2B_OUTBYTES)
{
blake2b_final(state, mResult, mLength);
blake2bp_init(mState, mLength);
}

void Blake2BP::Update(const void *buffer, size_t length)
{
blake2bp_update(mState, (unsigned char *)buffer, length);
}

void Blake2BP::Final()
{
blake2bp_final(mState, mResult, mLength);
}

Blake2S::Blake2S():Blake2Algorithm(BLAKE2S_OUTBYTES)
{
blake2s_init(mState, mLength);
}

void Blake2S::Update(const void *buffer, size_t length)
{
blake2s_update(mState, (unsigned char *)buffer, length);
}

void Blake2S::Final()
{
blake2s_final(mState, mResult, mLength);
}

Blake2SP::Blake2SP():Blake2Algorithm(BLAKE2S_OUTBYTES)
{
blake2sp_init(mState, mLength);
}

void Blake2SP::Update(const void *buffer, size_t length)
{
blake2sp_update(mState, (unsigned char *)buffer, length);
}

void Blake2SP::Final()
{
blake2sp_final(mState, mResult, mLength);
}

// --- v8 module ceremony

NAN_MODULE_INIT(AvonStream::Initialize)
{
v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);

t->SetClassName(Nan::New<String>("AvonStream").ToLocalChecked());
t->InstanceTemplate()->SetInternalFieldCount(2);

Nan::SetPrototypeMethod(t, "update", AvonStream::Update);
Nan::SetPrototypeMethod(t, "final", AvonStream::Final);

constructor().Reset(Nan::GetFunction(t).ToLocalChecked());
Nan::Set(target, Nan::New("AvonStream").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked());
}

0 comments on commit 9e33bb4

Please sign in to comment.