provided which use Web Workers in the browser or Worker threads in NodeJS.
Inputs can be passed as Uint8Array byte arrays (preferable) or strings. The
-output will return the same type as the input.
+output will return the same type as the input. A preallocated output buffer can
+be passed as an additional optional argument to the sync versions of `derive()`
+and `sign()` into which the result bytes will be written.
### Derive
```javascript
-// `prv` is a 32-byte Uint8Array private key
-const prv = new Uint8Array(32);
-const pub = nano25519.derive(prvBytes);
+// `prv` is a 32-byte private key
+const prv = new Uint8Array(usersPrivateKeyBuffer);
+
// `pub` is a 32-byte Uint8Array public key for a Nano account
+const pub = nano25519.derive(prv);
+// clean up
+prv.fill(0);
+```
+
+### Derive into preallocated buffer
+
+```javascript
+// `prv` is a 32-byte private key
+const prv = new Uint8Array(usersPrivateKeyBuffer);
+// `pub` is an empty 32-byte Uint8Array
+const pub = new Uint8Array(32);
+
+// return discarded, 32-byte public key is written to `pub`
+nano25519.derive(prv, pub);
+// clean up
+prv.fill(0);
```
### Derive (async)
```javascript
// `prv` is a 64-character hex string private key
const prv = "0000000000000000000000000000000000000000000000000000000000000000";
-const pub = await nano25519.deriveAsync(prv);
+
// `pub` is a 64-character hex string public key for a Nano account
+const pub = await nano25519.deriveAsync(prv);
```
### Sign
```javascript
-// `msg` is a 32-byte Uint8Array hash of a valid Nano transaction block
-const msg = 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 = nano25519.derive(prv);
-// `sk` is a 64-byte Uint8Array secret key joining private and public keys
-const sk = new Uint8Array([...prv, ...pub]);
+// `msg` is a 32-byte hash of a valid Nano transaction block
+const msg = new Uint8Array(blockHashBuffer);
+// `sk` is a 64-byte secret key joining private and public keys
+const sk = new Uint8Array(joinPrivateKeyPublicKeyBuffer);
-const sig = nano25519.sign(msg, sk);
// `sig` is a 64-byte Uint8Array signature for the block hash
+const sig = nano25519.sign(msg, sk);
+// clean up
+sk.fill(0);
+```
+
+### Sign into preallocated buffer
+
+```javascript
+// `msg` is a 32-byte hash of a valid Nano transaction block
+const msg = new Uint8Array(blockHashBuffer);
+// `sk` is a 64-byte secret key joining private and public keys
+const sk = new Uint8Array(joinPrivateKeyPublicKeyBuffer);
+// `sig` is an empty 64-byte Uint8Array
+const sig = new Uint8Array(64);
+
+// return discarded, 64-byte signature is written to `sig`
+nano25519.sign(msg, sk);
+// clean up
+sk.fill(0);
```
### Sign (async)
// `sk` is a 128-char hex string secret key joining private and public keys
const sk = prv + pub;
-const sig = await nano25519.signAsync(msg, sk);
// `sig` is a 128-char hex string signature for the block hash
+const sig = await nano25519.signAsync(msg, sk);
```
### Verify
```javascript
-// `sig` is a 64-byte Uint8Array signature
-const sig = new Uint8Array(64);
-// `msg` is a 32-byte Uint8Array hash of a valid Nano transaction block
-const msg = new Uint8Array(32);
-// `pub` is a 32-byte Uint8Array public key for a Nano account
-const pub = new Uint8Array(32);
+// `sig` is a 64-byte signature
+const sig = new Uint8Array(signatureBuffer);
+// `msg` is a 32-byte hash of a valid Nano transaction block
+const msg = new Uint8Array(blockHashBuffer);
+// `pub` is a 32-byte public key for a Nano account
+const pub = new Uint8Array(usersPublicKeyBuffer);
-const v = nano25519.verify(sig, msg, pub);
// `v` is a boolean 'true' if the same `prv` that derives `pub` was also used to create `sig` by signing `msg`, else 'false'
+const v = nano25519.verify(sig, msg, pub);
```
### Verify (async)
// `pub` is a 64-char hex string public key for a Nano account
const pub = "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210";
-const v = await nano25519.verifyAsync(sig, msg, pub);
// `v` is a boolean 'true' if the same `prv` that derives `pub` was also used to create `sig` by signing `msg`, else 'false'
+const v = await nano25519.verifyAsync(sig, msg, pub);
```
## Notes
ge_scalarmult_base_tobytes(s, nonce)\r
\r
// Concatenate public key `A` and message `M` from parameter arguments:\r
- // `A = sk[0,32], M = m`\r
+ // `A = sk[32,63], M = m`\r
// Compute challenge hash using `s = (R || A || M)`\r
blake2b.init().update(changetype<usize>(s), 32).update(changetype<usize>(sk) + 32, 32).update(m, mlen).digest(hram)\r
sc_reduce(hram)\r
}
}) as Exports
- function derive (k: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> {
- out ??= new Uint8Array(32)
+ function derive (prv: unknown, pub?: unknown): string | Uint8Array<ArrayBuffer> | void {
+ const out = pub ?? new Uint8Array(32)
if (!(isBytes(out) && out.byteLength === 32)) {
throw new TypeError('Derive output buffer must be 32-byte Uint8Array<ArrayBuffer>')
}
let privateKey = new Uint8Array(32)
let buffer = new DataView(exports.memory.buffer)
try {
- privateKey.set(normalize('private key', 32, 32, k))
+ privateKey.set(normalize('private key', 32, 32, prv))
let inPtr = exports.getInputPointer()
for (let i = 0; i < 32; i++) {
buffer.setUint8(inPtr + i, privateKey[i])
out[i] = buffer.getUint8(outPtr + i)
}
clear(buffer)
- if (typeof k === 'string') {
+ if (typeof pub === 'undefined') {
+ return
+ } else if (typeof prv === 'string') {
let hex = ''
for (const byte of out) {
hex += byte.toString(16).padStart(2, '0')
*/
export function derive (k: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
/**
- * Nano public key derivation using WebAssembly. Public key bytes are written to
- * the user-supplied output buffer instead of being allocated internally.
- * Technically, the buffer is also returned for API consistency, but the
- * location in memory is the same as the output buffer, so the return value can
- * be ignored.
+ * Nano public key derivation using WebAssembly. Instead of allocating an output
+ * buffer internally for the return value, public key bytes are written to the
+ * the user-supplied output buffer.
* @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
* @param {Uint8Array<ArrayBuffer>} pub - buffer to receive 32-byte public key
- * @returns the same buffer allocated in memory to `pub`
*/
-export function derive (k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-export function derive (k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
+export function derive (k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): void
+export function derive (k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> | void {
return nano25519.derive(k, out)
}
export function sign (m: Uint8Array<ArrayBuffer>, k: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
/**
* Signing using WebAssembly. To sign Nano blocks, the message should be a
- * 32-byte block hash. Signature bytes are written to the user-supplied output
- * buffer instead of being allocated internally. Technically, the buffer is also
- * returned for API consistency, but the location in memory is the same as the
- * output buffer, so the return value can be ignored.
+ * 32-byte block hash. Instead of allocating an output buffer internally for the
+ * return value, signature bytes are written to the the user-supplied output
+ * buffer.
* @param {Uint8Array<ArrayBuffer>} m - Variable-byte-length message up to 32 KiB
* @param {Uint8Array<ArrayBuffer>} k - 64-byte secret key (prv + pub)
* @param {Uint8Array<ArrayBuffer>} out - buffer to receive 64-byte detached signature
- * @returns the same buffer allocated in memory to `s`
*/
-export function sign (m: Uint8Array<ArrayBuffer>, k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-export function sign (m: string | Uint8Array<ArrayBuffer>, k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
+export function sign (m: Uint8Array<ArrayBuffer>, k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): void
+export function sign (m: string | Uint8Array<ArrayBuffer>, k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> | void {
return nano25519.sign(m, k, out)
}
export function verify (s: string, m: string, k: string): boolean
/**
* Signature verification using WebAssembly. To verify Nano block signatures,
- * the message should be a 64-character block hash.
+ * the message should be a 32-byte block hash.
* @param {Uint8Array<ArrayBuffer>} s - 64-byte detached signature
* @param {Uint8Array<ArrayBuffer>} m - Variable-byte-length message up to 32 KiB
* @param {Uint8Array<ArrayBuffer>} k - 32-byte public key