From 18befd9de97e254e573e369364adbd81cce15aec Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Sat, 28 Dec 2019 18:50:08 +0300 Subject: [PATCH] node-addon-api (n-api) instead NAN (#14) * Remove inherits & safe-buffer * Add hooks via husky * Add clang-format * Make code more es6 * Update dev dependencies * Use n-api instead nan * Update years in LICENSE file * Remove appveyor and travis * Remove husky * Use prebuildify instead node-gyp * Add lint workflow for GH Actions * Add test workflow for GH Actions * Build package for publishing in GitHub Actions * Adjust README --- .clang-format | 111 ++++++++++++++ .github/workflows/build-test-package.yaml | 105 +++++++++++++ .github/workflows/lint.yaml | 45 ++++++ .gitignore | 1 + .travis.yml | 33 ---- LICENSE | 2 +- Makefile | 90 +++++++++++ README.md | 6 - appveyor.yml | 22 --- binding.gyp | 113 +++++++++----- bindings.js | 3 +- index.js | 5 - js.js | 1 - lib/api/index.js | 1 - lib/api/keccak.js | 27 ++-- lib/api/shake.js | 29 ++-- lib/keccak-state-reference.js | 1 - lib/keccak-state-unroll.js | 1 - lib/keccak.js | 4 +- package.json | 39 +++-- src/addon.cc | 179 ++++++++++------------ test/api-sha3.js | 2 - test/api-shake.js | 2 - test/index.js | 1 - test/js-keccak.js | 2 - test/vectors-keccak.js | 2 - test/vectors-sha3.js | 6 +- test/vectors-shake.js | 6 +- util/package-fix-packagejson.js | 47 ++++++ 29 files changed, 602 insertions(+), 284 deletions(-) create mode 100644 .clang-format create mode 100644 .github/workflows/build-test-package.yaml create mode 100644 .github/workflows/lint.yaml delete mode 100644 .travis.yml create mode 100644 Makefile delete mode 100644 appveyor.yml create mode 100755 util/package-fix-packagejson.js diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..4aad29c --- /dev/null +++ b/.clang-format @@ -0,0 +1,111 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never diff --git a/.github/workflows/build-test-package.yaml b/.github/workflows/build-test-package.yaml new file mode 100644 index 0000000..c9cb11a --- /dev/null +++ b/.github/workflows/build-test-package.yaml @@ -0,0 +1,105 @@ +name: Build addon, run tests and package + +on: + push: + pull_request: + +jobs: + build-and-test: + name: Build addon + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - macos-latest + - ubuntu-latest + - windows-latest + steps: + - name: Fetch code + uses: actions/checkout@v1 + with: + submodules: true + + - name: Install dependencies + run: yarn install --ignore-scripts + + - name: Build addon + run: make build-addon + + - name: Get minimal Node.js version from package.json (Linux & macOS) + id: node-version-nix + if: runner.os != 'Windows' + run: echo "::set-output name=version::$(node -p 'require("./package.json").engines.node.match(/(\d.*)$/)[0]')" + + - name: Use Node.js ${{ steps.node-version-nix.outputs.version }} (Linux & macOS) + if: runner.os != 'Windows' + uses: actions/setup-node@v1 + with: + node-version: ${{ steps.node-version-nix.outputs.version }} + + - name: Get minimal Node.js version from package.json (Windows) + id: node-version-win + if: runner.os == 'Windows' + run: echo "::set-output name=version::$(node -p 'require(\"./package.json\").engines.node.match(/(\d.*)$/)[0]')" + + - name: Use Node.js ${{ steps.node-version-win.outputs.version }} (Windows) + if: runner.os == 'Windows' + uses: actions/setup-node@v1 + with: + node-version: ${{ steps.node-version-win.outputs.version }} + + - name: Run tests for addon + run: make test-tap + + - name: Upload prebuilds + uses: actions/upload-artifact@v1 + with: + name: addon-${{ runner.os }} + path: prebuilds + + package: + name: Build package + needs: build-and-test + runs-on: ubuntu-latest + steps: + - name: Fetch code + uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Install dependencies + run: yarn install --ignore-scripts + + - name: Download macOS addon + uses: actions/download-artifact@v1 + with: + name: addon-macOS + + - name: Download Linux addon + uses: actions/download-artifact@v1 + with: + name: addon-Linux + + - name: Download Windows addon + uses: actions/download-artifact@v1 + with: + name: addon-Windows + + - name: Move addons to one folder + run: mkdir prebuilds && mv ./addon-*/* ./prebuilds/ + + - name: list + run: find prebuilds + + - name: Build package + run: make package + + - name: Get package version from package.json + id: pkg-version + run: echo "::set-output name=version::$(node -p 'require("./package.json").version')" + + - name: Upload package + uses: actions/upload-artifact@v1 + with: + name: package + path: keccak-${{ steps.pkg-version.outputs.version }}.tgz diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..48fa069 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,45 @@ +name: Lint C/C++ and JS code + +on: + push: + pull_request: + +jobs: + cpp: + name: Lint C/C++ code + runs-on: ubuntu-latest + steps: + - name: Fetch code + uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - uses: actions/cache@v1 + id: cache + with: + path: clang + key: clang-llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04 + + - name: Download clang-format + if: steps.cache.outputs.cache-hit != 'true' + run: wget -O- -q http://releases.llvm.org/9.0.0/$VER.tar.xz | tar xfJ - $VER/bin/clang-format && mv $VER clang + env: + VER: clang+llvm-9.0.0-x86_64-linux-gnu-ubuntu-18.04 + + - name: Run lint command + run: PATH=$PATH:./clang/bin/ make lint-cpp-ci + + js: + name: Lint JS code + runs-on: ubuntu-latest + steps: + - name: Fetch code + uses: actions/checkout@v1 + with: + fetch-depth: 1 + + - name: Install dependencies + run: yarn install --ignore-scripts + + - name: Run lint command + run: make lint-js diff --git a/.gitignore b/.gitignore index 9b18914..cae96bd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ coverage build node_modules +prebuilds npm-debug.log package-lock.json diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 319dffc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -sudo: false -os: - - linux - - osx -language: node_js -node_js: - - "5" - - "6" - - "8" - - "10" - - "11" - - "12" - - "13" -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 -env: - global: - - JOBS=2 - matrix: - - TEST_SUITE=unit -matrix: - fast_finish: true - include: - - os: linux - node_js: "10" - env: TEST_SUITE=lint -before_install: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-6; fi -script: npm run $TEST_SUITE diff --git a/LICENSE b/LICENSE index 6804d6c..85339f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 https://github.com/cryptocoinjs/keccak contributors +Copyright (c) 2016-2019 https://github.com/cryptocoinjs/keccak contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f504b14 --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +.PHONY: build-addon coverage coverage-lcov format format-cpp lint lint-cpp \ + lint-cpp-ci lint-js test test-tap + + +prebuildify = ./node_modules/.bin/prebuildify + +# hack, otherwise GitHub Actions for Windows: +# '.' is not recognized as an internal or external command, operable program or batch file. +build-addon: + $(prebuildify) --target node@10.0.0 --napi --strip && node -p "process.platform" + + +nyc = ./node_modules/.bin/nyc + +coverage: + $(nyc) node test/index.js + +coverage-lcov: coverage + $(nyc) report -r lcov + + +format_cpp_files = ./src/addon.cc + +format: format-cpp + +format-cpp: + clang-format -i -verbose $(format_cpp_files) + + +standard = ./node_modules/.bin/standard +lint_dir = build/lint + +lint: lint-cpp lint-js + +lint-cpp: + mkdir -p $(lint_dir)/cpp/src + rsync -a --delete src/ $(lint_dir)/cpp/src + cd $(lint_dir)/cpp && clang-format -i -verbose $(format_cpp_files) + git diff --no-index --exit-code src $(lint_dir)/cpp/src + +# `-verbose` not exists in clang-format@3.8 +# See https://github.com/actions/virtual-environments/issues/46 +lint-cpp-ci: + clang-format -i $(format_cpp_files) + git diff --exit-code --color=always + +lint-js: + $(standard) + + +package_dir = build/package +package_include_dirs = \ + lib \ + prebuilds \ + src +package_include_files = \ + binding.gyp \ + LICENSE \ + package.json \ + README.md + +package: package-copy-files package-fix-packagejson package-pack package-copy + +package-copy-files: + mkdir -p $(package_dir) + for loc in $(package_include_dirs); do \ + rsync -a --delete $$loc $(package_dir); \ + done + cp $(package_include_files) $(package_dir) + +package-fix-packagejson: + util/package-fix-packagejson.js -f $(package_dir)/package.json + +package-pack: + cd $(package_dir) && npm pack + +package-copy: + cp $(package_dir)/keccak-`node -p "require('./package.json').version"`.tgz . + + +tape = ./node_modules/.bin/tape +tap_reporter = ./node_modules/.bin/tap-dot +test_files = test/index.js + +test: + $(tape) $(test_files) | $(tap_reporter) + +# See build-addon +test-tap: + $(tape) $(test_files) && node -p "process.platform" diff --git a/README.md b/README.md index dbab97d..d468a2a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,5 @@ # keccak -Version | Mac/Linux | Windows -------- | --------- | ------- -[![NPM Package](https://img.shields.io/npm/v/keccak.svg?style=flat-square)](https://www.npmjs.org/package/keccak) | [![Build Status](https://img.shields.io/travis/cryptocoinjs/keccak.svg?branch=master&style=flat-square)](https://travis-ci.org/cryptocoinjs/keccak) | [![AppVeyor](https://img.shields.io/appveyor/ci/fanatid/keccak.svg?branch=master&style=flat-square)](https://ci.appveyor.com/project/fanatid/keccak) - -[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) - This module provides native bindings to [Keccak sponge function family][1] from [Keccak Code Package][2]. In browser pure JavaScript implementation will be used. ## Usage diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 7b49515..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: "{build}" -build: off -skip_tags: true -environment: - matrix: - - nodejs_version: "6" - - nodejs_version: "7" - - nodejs_version: "8" - - nodejs_version: "10" - - nodejs_version: "12" -platform: - - x86 - - x64 -install: - - git submodule update --init --recursive - - ps: Install-Product node $env:nodejs_version $env:platform - - npm --global install npm@latest - - set PATH=%APPDATA%\npm;%APPVEYOR_BUILD_FOLDER%\node_modules\.bin;%PATH% - - npm install - - for /f %%i in ('node -v') do set exact_nodejs_version=%%i -test_script: - - npm run unit diff --git a/binding.gyp b/binding.gyp index 2971268..39ea378 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,45 +1,78 @@ { - "variables": { - "arch": " class Keccak extends Transform { + constructor (rate, capacity, delimitedSuffix, hashBitLength, options) { + super(options) this._rate = rate this._capacity = capacity @@ -18,9 +15,7 @@ module.exports = function (KeccakState) { this._finalized = false } - inherits(Keccak, Transform) - - Keccak.prototype._transform = function (chunk, encoding, callback) { + _transform (chunk, encoding, callback) { let error = null try { this.update(chunk, encoding) @@ -31,7 +26,7 @@ module.exports = function (KeccakState) { callback(error) } - Keccak.prototype._flush = function (callback) { + _flush (callback) { let error = null try { this.push(this.digest()) @@ -42,7 +37,7 @@ module.exports = function (KeccakState) { callback(error) } - Keccak.prototype.update = function (data, encoding) { + update (data, encoding) { if (!Buffer.isBuffer(data) && typeof data !== 'string') throw new TypeError('Data must be a string or a buffer') if (this._finalized) throw new Error('Digest already called') if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding) @@ -52,7 +47,7 @@ module.exports = function (KeccakState) { return this } - Keccak.prototype.digest = function (encoding) { + digest (encoding) { if (this._finalized) throw new Error('Digest already called') this._finalized = true @@ -66,19 +61,17 @@ module.exports = function (KeccakState) { } // remove result from memory - Keccak.prototype._resetState = function () { + _resetState () { this._state.initialize(this._rate, this._capacity) return this } // because sometimes we need hash right now and little later - Keccak.prototype._clone = function () { + _clone () { const clone = new Keccak(this._rate, this._capacity, this._delimitedSuffix, this._hashBitLength, this._options) this._state.copy(clone._state) clone._finalized = this._finalized return clone } - - return Keccak } diff --git a/lib/api/shake.js b/lib/api/shake.js index c8d6a96..a890aa7 100644 --- a/lib/api/shake.js +++ b/lib/api/shake.js @@ -1,11 +1,8 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer -const Transform = require('stream').Transform -const inherits = require('inherits') +const { Transform } = require('stream') -module.exports = function (KeccakState) { - function Shake (rate, capacity, delimitedSuffix, options) { - Transform.call(this, options) +module.exports = (KeccakState) => class Shake extends Transform { + constructor (rate, capacity, delimitedSuffix, options) { + super(options) this._rate = rate this._capacity = capacity @@ -17,9 +14,7 @@ module.exports = function (KeccakState) { this._finalized = false } - inherits(Shake, Transform) - - Shake.prototype._transform = function (chunk, encoding, callback) { + _transform (chunk, encoding, callback) { let error = null try { this.update(chunk, encoding) @@ -30,13 +25,13 @@ module.exports = function (KeccakState) { callback(error) } - Shake.prototype._flush = function () {} + _flush () {} - Shake.prototype._read = function (size) { + _read (size) { this.push(this.squeeze(size)) } - Shake.prototype.update = function (data, encoding) { + update (data, encoding) { if (!Buffer.isBuffer(data) && typeof data !== 'string') throw new TypeError('Data must be a string or a buffer') if (this._finalized) throw new Error('Squeeze already called') if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding) @@ -46,7 +41,7 @@ module.exports = function (KeccakState) { return this } - Shake.prototype.squeeze = function (dataByteLength, encoding) { + squeeze (dataByteLength, encoding) { if (!this._finalized) { this._finalized = true this._state.absorbLastFewBits(this._delimitedSuffix) @@ -58,18 +53,16 @@ module.exports = function (KeccakState) { return data } - Shake.prototype._resetState = function () { + _resetState () { this._state.initialize(this._rate, this._capacity) return this } - Shake.prototype._clone = function () { + _clone () { const clone = new Shake(this._rate, this._capacity, this._delimitedSuffix, this._options) this._state.copy(clone._state) clone._finalized = this._finalized return clone } - - return Shake } diff --git a/lib/keccak-state-reference.js b/lib/keccak-state-reference.js index d6918e7..8248d34 100644 --- a/lib/keccak-state-reference.js +++ b/lib/keccak-state-reference.js @@ -1,4 +1,3 @@ -'use strict' const P1600_RHO_OFFSETS = [0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14] const P1600_ROUND_CONSTANTS = [ 0x00000001, 0x00000000, diff --git a/lib/keccak-state-unroll.js b/lib/keccak-state-unroll.js index 790bdf4..38a8500 100644 --- a/lib/keccak-state-unroll.js +++ b/lib/keccak-state-unroll.js @@ -1,4 +1,3 @@ -'use strict' const P1600_ROUND_CONSTANTS = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649, 0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0, 2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771, 2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648, 2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648] exports.p1600 = function (s) { diff --git a/lib/keccak.js b/lib/keccak.js index 64ecd94..8512380 100644 --- a/lib/keccak.js +++ b/lib/keccak.js @@ -1,5 +1,3 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer const keccakState = require('./keccak-state-unroll') function Keccak () { @@ -48,7 +46,7 @@ Keccak.prototype.squeeze = function (length) { if (!this.squeezing) this.absorbLastFewBits(0x01) const output = Buffer.alloc(length) - for (var i = 0; i < length; ++i) { + for (let i = 0; i < length; ++i) { output[i] = (this.state[~~(this.count / 4)] >>> (8 * (this.count % 4))) & 0xff this.count += 1 if (this.count === this.blockSize) { diff --git a/package.json b/package.json index 56b1ea3..c621a31 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,17 @@ "bugs": { "url": "https://github.com/cryptocoinjs/keccak/issues" }, + "repository": { + "type": "git", + "url": "https://github.com/cryptocoinjs/keccak.git" + }, "license": "MIT", "contributors": [ "Kirill Fomichev (https://github.com/fanatid)" ], "files": [ "lib", + "prebuilds", "src", "binding.gyp", "bindings.js", @@ -24,37 +29,29 @@ "js.js" ], "main": "./index.js", - "repository": { - "type": "git", - "url": "https://github.com/cryptocoinjs/keccak.git" + "browser": { + "./index.js": "./js.js" }, "scripts": { - "coverage": "nyc tape test/index.js", - "coverage-lcov": "npm run coverage && nyc report -r lcov", - "install": "npm run rebuild || echo \"Keccak bindings compilation fail. Pure JS implementation will be used.\"", - "lint": "standard", - "rebuild": "node-gyp rebuild", - "test": "npm run lint && npm run unit", - "unit": "tape test/index.js" + "install": "node-gyp-build || exit 0" }, "dependencies": { - "bindings": "^1.5.0", - "inherits": "^2.0.4", - "nan": "^2.14.0", - "safe-buffer": "^5.2.0" + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" }, "devDependencies": { "browserify": "^16.5.0", - "nyc": "^14.1.1", + "node-gyp": "^5.0.7", + "nyc": "^15.0.0", + "prebuildify": "^3.0.4", "proxyquire": "^2.1.3", "standard": "^14.3.1", - "tape": "^4.11.0" + "tap-dot": "^2.0.0", + "tape": "^4.12.0", + "yargs": "^15.0.2" }, "engines": { - "node": ">=5.12.0" + "node": ">=10.0.0" }, - "gypfile": true, - "browser": { - "./index.js": "./js.js" - } + "gypfile": true } diff --git a/src/addon.cc b/src/addon.cc index ecc1542..3ec1cf6 100644 --- a/src/addon.cc +++ b/src/addon.cc @@ -1,109 +1,98 @@ -#include -#include +#include extern "C" { -#if LIBKECCAK == 32 - #include "libkeccak-32/KeccakSpongeWidth1600.h" -#elif LIBKECCAK == 64 - #include "libkeccak-64/KeccakSpongeWidth1600.h" -#else - #error "LIBKECCAK not defined correctly" -#endif +#include } -class KeccakWrapper : public Nan::ObjectWrap { +class KeccakWrapper : public Napi::ObjectWrap { public: - static v8::Local Init () { - Nan::EscapableHandleScope scope; + static Napi::Object Init(Napi::Env env); - v8::Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("KeccakWrapper").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - Nan::SetPrototypeMethod(tpl, "initialize", Initialize); - Nan::SetPrototypeMethod(tpl, "absorb", Absorb); - Nan::SetPrototypeMethod(tpl, "absorbLastFewBits", AbsorbLastFewBits); - Nan::SetPrototypeMethod(tpl, "squeeze", Squeeze); - Nan::SetPrototypeMethod(tpl, "copy", Copy); - - return scope.Escape(Nan::GetFunction(tpl).ToLocalChecked()); - } + KeccakWrapper(const Napi::CallbackInfo& info); private: KeccakWidth1600_SpongeInstance sponge; + static Napi::FunctionReference constructor; - static NAN_METHOD(New) { - KeccakWrapper* obj = new KeccakWrapper(); - obj->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - } - - static NAN_METHOD(Initialize) { - KeccakWrapper* obj = Nan::ObjectWrap::Unwrap(info.Holder()); -#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION) - unsigned int rate = info[0]->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked(); - unsigned int capacity = info[1]->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked(); -#else - unsigned int rate = info[0]->IntegerValue(); - unsigned int capacity = info[1]->IntegerValue(); -#endif - - // ignore return code, rate & capacity always will right because internal object - KeccakWidth1600_SpongeInitialize(&obj->sponge, rate, capacity); - } - - static NAN_METHOD(Absorb) { - KeccakWrapper* obj = Nan::ObjectWrap::Unwrap(info.Holder()); - v8::Local buffer = info[0].As(); - const unsigned char* data = (const unsigned char*) node::Buffer::Data(buffer); - size_t length = node::Buffer::Length(buffer); - - // ignore return code, bcause internal object - KeccakWidth1600_SpongeAbsorb(&obj->sponge, data, length); - } - - static NAN_METHOD(AbsorbLastFewBits) { - KeccakWrapper* obj = Nan::ObjectWrap::Unwrap(info.Holder()); -#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION) - unsigned char bits = info[0]->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked(); -#else - unsigned char bits = info[0]->IntegerValue(); -#endif - - // ignore return code, bcause internal object - KeccakWidth1600_SpongeAbsorbLastFewBits(&obj->sponge, bits); - } - - static NAN_METHOD(Squeeze) { - KeccakWrapper* obj = Nan::ObjectWrap::Unwrap(info.Holder()); -#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION) - size_t length = info[0]->IntegerValue(info.GetIsolate()->GetCurrentContext()).ToChecked(); -#else - size_t length = info[0]->IntegerValue(); -#endif - - v8::Local buffer = Nan::NewBuffer(length).ToLocalChecked(); - unsigned char* data = (unsigned char*) node::Buffer::Data(buffer); - - KeccakWidth1600_SpongeSqueeze(&obj->sponge, data, length); - info.GetReturnValue().Set(buffer); - } - - static NAN_METHOD(Copy) { - KeccakWrapper* from = Nan::ObjectWrap::Unwrap(info.Holder()); -#if (NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION) - KeccakWrapper* to = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); -#else - KeccakWrapper* to = Nan::ObjectWrap::Unwrap(info[0]->ToObject()); -#endif - - memcpy(&to->sponge, &from->sponge, sizeof(KeccakWidth1600_SpongeInstance)); - } + Napi::Value Initialize(const Napi::CallbackInfo& info); + Napi::Value Absorb(const Napi::CallbackInfo& info); + Napi::Value AbsorbLastFewBits(const Napi::CallbackInfo& info); + Napi::Value Squeeze(const Napi::CallbackInfo& info); + Napi::Value Copy(const Napi::CallbackInfo& info); }; -void Init(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE exports, Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE module) { - // I wish to use pure functions, but we need wrapper around state (KeccakWidth1600_SpongeInstance) - Nan::Set(module, Nan::New("exports").ToLocalChecked(), KeccakWrapper::Init()); +Napi::FunctionReference KeccakWrapper::constructor; + +Napi::Object KeccakWrapper::Init(Napi::Env env) { + Napi::Function func = + DefineClass(env, + "KeccakWrapper", + { + InstanceMethod("initialize", &KeccakWrapper::Initialize), + InstanceMethod("absorb", &KeccakWrapper::Absorb), + InstanceMethod("absorbLastFewBits", + &KeccakWrapper::AbsorbLastFewBits), + InstanceMethod("squeeze", &KeccakWrapper::Squeeze), + InstanceMethod("copy", &KeccakWrapper::Copy), + }); + + constructor = Napi::Persistent(func); + constructor.SuppressDestruct(); + + return func; +} + +KeccakWrapper::KeccakWrapper(const Napi::CallbackInfo& info) + : Napi::ObjectWrap(info) {} + +Napi::Value KeccakWrapper::Initialize(const Napi::CallbackInfo& info) { + auto rate = info[0].As().Uint32Value(); + auto capacity = info[1].As().Uint32Value(); + + // ignore return code, + // rate & capacity always will right because internal object + KeccakWidth1600_SpongeInitialize(&sponge, rate, capacity); + + return info.Env().Undefined(); +} + +Napi::Value KeccakWrapper::Absorb(const Napi::CallbackInfo& info) { + auto buf = info[0].As>(); + + // ignore return code, bcause internal object + KeccakWidth1600_SpongeAbsorb(&sponge, buf.Data(), buf.Length()); + + return info.Env().Undefined(); +} + +Napi::Value KeccakWrapper::AbsorbLastFewBits(const Napi::CallbackInfo& info) { + auto bits = info[0].As().Uint32Value(); + + // ignore return code, bcause internal object + KeccakWidth1600_SpongeAbsorbLastFewBits(&sponge, bits); + + return info.Env().Undefined(); +} + +Napi::Value KeccakWrapper::Squeeze(const Napi::CallbackInfo& info) { + auto length = info[0].As().Uint32Value(); + auto buf = Napi::Buffer::New(info.Env(), length); + + KeccakWidth1600_SpongeSqueeze(&sponge, buf.Data(), length); + + return buf; +} + +Napi::Value KeccakWrapper::Copy(const Napi::CallbackInfo& info) { + auto to = Napi::ObjectWrap::Unwrap(info[0].As()); + + memcpy(&to->sponge, &sponge, sizeof(KeccakWidth1600_SpongeInstance)); + + return info.Env().Undefined(); +} + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + return KeccakWrapper::Init(env); } -NODE_MODULE(keccak, Init) +NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/api-sha3.js b/test/api-sha3.js index 879c6f2..eb1175b 100644 --- a/test/api-sha3.js +++ b/test/api-sha3.js @@ -1,5 +1,3 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer const test = require('tape') const utf8text = 'УТФ-8 text' diff --git a/test/api-shake.js b/test/api-shake.js index 92136c5..8e4913c 100644 --- a/test/api-shake.js +++ b/test/api-shake.js @@ -1,5 +1,3 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer const test = require('tape') const stream = require('stream') diff --git a/test/index.js b/test/index.js index f350645..da8831b 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,3 @@ -'use strict' const test = require('tape') function main (name, createHash) { diff --git a/test/js-keccak.js b/test/js-keccak.js index 9a6bfcf..8cd476f 100644 --- a/test/js-keccak.js +++ b/test/js-keccak.js @@ -1,5 +1,3 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer const test = require('tape') const proxyquire = require('proxyquire') diff --git a/test/vectors-keccak.js b/test/vectors-keccak.js index 442a4f4..e8a5f63 100644 --- a/test/vectors-keccak.js +++ b/test/vectors-keccak.js @@ -1,5 +1,3 @@ -'use strict' -const Buffer = require('safe-buffer').Buffer const test = require('tape') const vectors = [{ diff --git a/test/vectors-sha3.js b/test/vectors-sha3.js index 0fa7d08..95da8da 100644 --- a/test/vectors-sha3.js +++ b/test/vectors-sha3.js @@ -1,4 +1,3 @@ -'use strict' const test = require('tape') const fs = require('fs') @@ -6,10 +5,9 @@ module.exports = (name, createHash) => { for (const hash of ['sha3-224', 'sha3-256', 'sha3-384', 'sha3-512']) { const filename = require.resolve(`../util/XKCP/tests/TestVectors/ShortMsgKAT_${hash.toUpperCase()}.txt`) const content = fs.readFileSync(filename, 'utf8') - const lines = content.split('\n') + const lines = content.split('\n').map((x) => x.trim()) - let count = 0 - for (let i = 0; i < lines.length; ++i) { + for (let i = 0, count = 0; i < lines.length; ++i) { if (!lines[i].startsWith('Len')) continue const length = parseInt(lines[i].slice(6), 10) diff --git a/test/vectors-shake.js b/test/vectors-shake.js index c2bb1f2..38edfc1 100644 --- a/test/vectors-shake.js +++ b/test/vectors-shake.js @@ -1,4 +1,3 @@ -'use strict' const test = require('tape') const fs = require('fs') @@ -6,10 +5,9 @@ module.exports = (name, createHash) => { for (const hash of ['shake128', 'shake256']) { const filename = require.resolve(`../util/XKCP/tests/TestVectors/ShortMsgKAT_${hash.toUpperCase()}.txt`) const content = fs.readFileSync(filename, 'utf8') - const lines = content.split('\n') + const lines = content.split('\n').map((x) => x.trim()) - let count = 0 - for (let i = 0; i < lines.length; ++i) { + for (let i = 0, count = 0; i < lines.length; ++i) { if (!lines[i].startsWith('Len')) continue const length = parseInt(lines[i].slice(6), 10) diff --git a/util/package-fix-packagejson.js b/util/package-fix-packagejson.js new file mode 100755 index 0000000..03e233c --- /dev/null +++ b/util/package-fix-packagejson.js @@ -0,0 +1,47 @@ +#!/usr/bin/env node +const fs = require('fs') +const yargs = require('yargs') + +const fields = [ + 'name', + 'version', + 'description', + 'keywords', + 'bugs', + 'repository', + 'license', + 'author', + 'contributors', + 'main', + 'browser', + 'scripts', + 'dependencies', + 'engines', + 'gypfile' +] + +function getArgs () { + return yargs + .usage('Usage: $0 [options]') + .wrap(yargs.terminalWidth()) + .options({ + file: { + alias: 'f', + description: 'Path to package.json', + type: 'string' + } + }) + .help('help') + .alias('help', 'h').argv +} + +const args = getArgs() +const pkg = JSON.parse(fs.readFileSync(args.file, 'utf8')) + +const fixedPkg = {} +for (const [key, value] of Object.entries(pkg)) { + if (fields.includes(key)) fixedPkg[key] = value +} + +const content = JSON.stringify(fixedPkg, null, 2) +fs.writeFileSync(args.file, content)