_Block signing and validation for Nano cryptocurrency using WebAssembly._
-NanoNaCl is an AssemblyScript port of tweetnacl-js, modified to hash using
-BLAKE2b instead of SHA-512 as specified for Nano cryptocurrency. It can derive
-public keys from private keys, sign blocks, and verify block signatures. All
-processing takes place client-side and offline.
+NanoNaCl is an AssemblyScript implementation of select Ed25519 functions used by
+the Nano cryptocurrency. It is modified to hash using BLAKE2b instead of SHA-512
+and can derive public keys from private keys, sign blocks, and verify block
+signatures. All processing takes place client-side and offline.
For more information about the public key derivation algorithm used by Nano, see
<https://docs.nano.org/integration-guides/the-basics/#account-public-key>
npm i nano-nacl
```
-## Usage
-
-### Import
-
-The easiest way to use NanoNaCl is to import it into your NodeJS project.
-
-```javascript
-import { derive, sign, verify } from "nano-nacl";
-// OR
-import * as NanoNaCl from "nano-nacl";
-```
+### Browser
-You can also use it directly on a webpage with a script module:
+NanoNaCl can be used directly on a webpage with a script module:
```html
<script type="module">
</script>
```
+### NodeJS
+
+NanoNaCl can be imported into NodeJS projects:
+
+```javascript
+import { derive, sign, verify } from "nano-nacl";
+```
+
+## Usage
+
+Each function has a synchronous implementation which is preferable for speed.
+These versions require Uint8Array byte arrays and return the same.
+
+If a non-blocking solution is required, asynchronous implementations are
+provided which use Web Workers in the browser or Worker threads in NodeJS. These
+versions require hex strings and return the same.
+
### Derive
```javascript
-// `sk` is a 64-char hex string secret key
-const sk = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
+// `prv` is a 32-byte Uint8Array private key
+const prv = new Uint8Array(32);
+const pub = NanoNaCl.derive(prvBytes);
+// `pub` is a 32-byte Uint8Array public key for a Nano account
+```
+
+### Derive (async)
-const pk = await NanoNaCl.derive(sk);
-// `pk` is a 64-char hex string public key for a Nano account
+```javascript
+// `prv` is a 64-character hex string private key
+const prv = "0000000000000000000000000000000000000000000000000000000000000000";
+const pub = await NanoNaCl.deriveAsync(prv);
+// `pub` is a 64-character hex string public key for a Nano account
```
### Sign
+```javascript
+// `hash` is a 32-byte Uint8Array hash of a valid Nano transaction block
+const hash = new Uint8Array(32);
+// `prv` is a 32-byte Uint8Array private key
+const prv = new Uint8Array(32);
+// `pub` is a 32-byte Uint8Array public key derived from `prv`
+const pub = NanoNaCl.derive(prv);
+// `sk` is a 64-byte Uint8Array secret key joining private and public keys
+const sk = new Uint8Array([...prv, ...pub]);
+
+const sig = NanoNaCl.sign(hash, sk);
+// `sig` is a 64-byte Uint8Array signature for the block hash
+```
+
+### Sign (async)
+
```javascript
// `hash` is a 64-char hex string hash of a valid Nano transaction block
const hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
-// `sk` is a 64-char hex string secret key
-const sk = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
-
-const sig = await NanoNaCl.sign(hash, sk);
+// `prv` is a 64-char hex string private key
+const prv = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
+// `pub` is a 64-char hex string public key derived from `prv`
+const pub = await NanoNaCl.deriveAsync(prv);
+// `sk` is a 128-char hex string secret key joining private and public keys
+const sk = prv + pub;
+
+const sig = await NanoNaCl.signAsync(hash, sk);
// `sig` is a 128-char hex string signature on the blockhash
```
### Verify
```javascript
-// `hash` is a 64-char hex string hash of a valid Nano transaction block
-const hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
-// `sig` is a 128-char hex string signature on the blockhash
+// `sig` is a 64-byte Uint8Array signature on a block hash
+const sig = new Uint8Array(64);
+// `hash` is a 32-byte Uint8Array hash of a valid Nano transaction block
+const hash = new Uint8Array(32);
+// `pub` is a 32-byte Uint8Array public key for a Nano account
+const pub = new Uint8Array(32);
+
+const v = NanoNaCl.verify(sig, hash, pub);
+// `v` is a boolean 'true' if the same `prv` that derives `pub` was also used to create `sig` by signing `hash`, else 'false'
+```
+
+### Verify (async)
+
+```javascript
+// `sig` is a 128-char hex string signature on a block hash
const sig =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
-// `pk` is a 64-char hex string public key for a Nano account
-const pk = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
+// `hash` is a 64-char hex string hash of a valid Nano transaction block
+const hash = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
+// `pub` is a 64-char hex string public key for a Nano account
+const pub = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
-const v = await NanoNaCl.verify(hash, sig, pk);
-// `v` is a boolean 'true' if `pk` was used to sign `hash` with `sig`, else 'false'
+const v = await NanoNaCl.verifyAsync(sig, hash, pub);
+// `v` is a boolean 'true' if the same `prv` that derives `pub` was also used to create `sig` by signing `hash`, else 'false'
```
## Notes
-The tweetnacl-js implementation was selected as the basis for NanoNaCl due to
-its historical reliability and security. For this project, it has been altered
-to use BLAKE2b as its internal hashing algorithm instead of SHA-512. It has also
-been optimized for Nano cryptocurrency needs, and many tweetnacl-js functions
-have been removed due to the very narrow use case to which it is applied here.
+The tweetnacl-js implementation was originally selected as the basis for
+NanoNaCl due to its historical reliability and security. Over time, however, it
+became clear that tweetnacl was designed to optimize size and not speed. Soon
+after, libsodium became the reference from which functionality was ported.
+
+For this project, the internal hash mechanism was altered to use BLAKE2b
+instead of SHA-512 so that it aligns with the Nano protocol. It has also been
+optimized specifically for Nano needs; many functions have been modified or
+removed due to the very narrow use case to which it is applied here.
## Tests
A few basic tests are availabe in the source repository.
-- `test/index.html` in the source repository contains a web interface to change
- execution options and compare results.
+- `index.html` is a web interface to test browser execution and compare
+ performance with other browser-based implementations.
+- `test.mjs` is a basic test for NodeJS to check result validity.
## Building
1. Compile, minify, and bundle
```console
-git clone https://git.codecow.com/nano-nacl.git
+git clone https://codecow.com/nano-nacl.git
cd nano-nacl
npm i
```
## Licenses
GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
-tweetnacl-js is public domain under the Unlicense and was copied from the
+
+libsodium is distributed under the ISC license and was referenced from the
+following commit hash:
+<https://github.com/jedisct1/libsodium/tree/d24faf56214469b354b01c8ba36257e04737101e>
+
+tweetnacl-js is public domain under the Unlicense and was referenced from the
following commit hash:
<https://github.com/dchest/tweetnacl-js/tree/e6141a20553498697e9e7d92fbc4517994caff52>