// Static I/O buffers
const INPUT_BUFFER_BYTES: i32 = SIGNATURE_BYTES + MESSAGE_BYTES
-const OUTPUT_BUFFER_BYTES: i32 = SIGNATURE_BYTES
const MESSAGE_BUFFER_BYTES: i32 = 32768
-const INPUT_BUFFER = memory.data(INPUT_BUFFER_BYTES)
-const OUTPUT_BUFFER = memory.data(OUTPUT_BUFFER_BYTES)
-const MESSAGE_BUFFER = memory.data(MESSAGE_BUFFER_BYTES)
-
-/** Returns the pointer to the static output buffer (64 bytes). */
-export function getOutputPointer (): usize {
- return OUTPUT_BUFFER
-}
+const OUTPUT_BUFFER_BYTES: i32 = SIGNATURE_BYTES
+const INPUT_BUFFER = new StaticArray<u8>(INPUT_BUFFER_BYTES)
+const MESSAGE_BUFFER = new StaticArray<u8>(MESSAGE_BUFFER_BYTES)
+const OUTPUT_BUFFER = new StaticArray<u8>(OUTPUT_BUFFER_BYTES)
/** Returns the pointer to the static input buffer (128 bytes). */
export function getInputPointer (): usize {
- return INPUT_BUFFER
+ return changetype<usize>(INPUT_BUFFER)
}
/** Returns the pointer to the static message buffer (32 KiB). */
export function getMessagePointer (): usize {
- return MESSAGE_BUFFER
+ return changetype<usize>(MESSAGE_BUFFER)
+}
+
+/** Returns the pointer to the static output buffer (64 bytes). */
+export function getOutputPointer (): usize {
+ return changetype<usize>(OUTPUT_BUFFER)
}
-const derive_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
const derive_prv = new StaticArray<u8>(PRIVATEKEY_BYTES)
+const derive_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
/**
* Derive a 32-byte Nano public key from a 32-byte private key. Parameters are
* read as bytes from the input buffer in the following order:
* The public key is written to the output buffer.
*/
export function derive (): void {
- const pub = derive_pub
- const prv = derive_prv
+ // Clear local buffers
+ derive_prv.fill(0)
+ derive_pub.fill(0)
+
+ // Copy input buffer to local parameterss, then clear input buffer
+ memory.copy(changetype<usize>(derive_prv), changetype<usize>(INPUT_BUFFER), PRIVATEKEY_BYTES)
+ INPUT_BUFFER.fill(0)
+
+ // Derive, then clear local input
+ crypto_derive(derive_pub, derive_prv)
+ derive_prv.fill(0)
- memory.copy(changetype<usize>(prv), INPUT_BUFFER, PRIVATEKEY_BYTES)
- memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES)
+ // Clear output buffer of prior data, then copy local result to output buffer
+ OUTPUT_BUFFER.fill(0)
+ memory.copy(changetype<usize>(OUTPUT_BUFFER), changetype<usize>(derive_pub), PUBLICKEY_BYTES)
- crypto_derive(pub, prv)
- memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
- memory.copy(OUTPUT_BUFFER, changetype<usize>(pub), PUBLICKEY_BYTES)
+ // Clear local result
+ derive_pub.fill(0)
}
-const sign_sig = new StaticArray<u8>(SIGNATURE_BYTES)
+const sign_msg = new StaticArray<u8>(MESSAGE_BUFFER_BYTES)
const sign_prv = new StaticArray<u8>(PRIVATEKEY_BYTES)
const sign_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
+const sign_sig = new StaticArray<u8>(SIGNATURE_BYTES)
/**
* Sign up to 32 KiB of data using a 64-byte secret key. Parameters are read as
* bytes from the input buffer in the following order:
*/
export function sign (mlen: i32): void {
if (mlen < 0 || mlen > 32768) throw new Error()
- const sig = sign_sig
- const prv = sign_prv
- const pub = sign_pub
-
- memory.copy(changetype<usize>(prv), INPUT_BUFFER, PRIVATEKEY_BYTES)
- memory.copy(changetype<usize>(pub), INPUT_BUFFER + PRIVATEKEY_BYTES, PUBLICKEY_BYTES)
- memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES)
- const msg = changetype<StaticArray<u8>>(MESSAGE_BUFFER)
-
- crypto_sign(sig, msg, mlen, prv, pub)
- memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
- memory.copy(OUTPUT_BUFFER, changetype<usize>(sig), SIGNATURE_BYTES)
+ // Clear local buffers
+ sign_msg.fill(0)
+ sign_prv.fill(0)
+ sign_pub.fill(0)
+ sign_sig.fill(0)
+
+ // Copy input buffer to local parameters, then clear input buffer
+ memory.copy(changetype<usize>(sign_prv), changetype<usize>(INPUT_BUFFER), PRIVATEKEY_BYTES)
+ memory.copy(changetype<usize>(sign_pub), changetype<usize>(INPUT_BUFFER) + PRIVATEKEY_BYTES, PUBLICKEY_BYTES)
+ INPUT_BUFFER.fill(0)
+
+ // Copy message buffer to local variable, then clear message buffer
+ memory.copy(changetype<usize>(sign_msg), changetype<usize>(MESSAGE_BUFFER), mlen)
+ MESSAGE_BUFFER.fill(0)
+
+ // Sign, then clear local input
+ crypto_sign(sign_sig, sign_msg, mlen, sign_prv, sign_pub)
+ sign_msg.fill(0)
+ sign_prv.fill(0)
+ sign_pub.fill(0)
+
+ // Clear output buffer of prior data, then copy local result to output buffer
+ OUTPUT_BUFFER.fill(0)
+ memory.copy(changetype<usize>(OUTPUT_BUFFER), changetype<usize>(sign_sig), SIGNATURE_BYTES)
+
+ // Clear local result
+ sign_sig.fill(0)
}
-const verify_sig = new StaticArray<u8>(SIGNATURE_BYTES)
+const verify_msg = new StaticArray<u8>(MESSAGE_BUFFER_BYTES)
const verify_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
+const verify_sig = new StaticArray<u8>(SIGNATURE_BYTES)
/**
* Verify a 64-byte detached signature for a variable-length message against a
* 32-byte public key. Parameters are read as bytes from the input buffer in the
*/
export function verify (mlen: i32): i32 {
if (mlen < 0 || mlen > 32768) throw new Error('invalid message length')
- const sig = verify_sig
- const pub = verify_pub
- memory.copy(changetype<usize>(sig), INPUT_BUFFER, SIGNATURE_BYTES)
- memory.copy(changetype<usize>(pub), INPUT_BUFFER + SIGNATURE_BYTES, PUBLICKEY_BYTES)
- memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES)
+ // Clear local buffers
+ verify_msg.fill(0)
+ verify_pub.fill(0)
+ verify_sig.fill(0)
+
+ // Copy input buffer to local parameters, then clear input buffer
+ memory.copy(changetype<usize>(verify_sig), changetype<usize>(INPUT_BUFFER), SIGNATURE_BYTES)
+ memory.copy(changetype<usize>(verify_pub), changetype<usize>(INPUT_BUFFER) + SIGNATURE_BYTES, PUBLICKEY_BYTES)
+ INPUT_BUFFER.fill(0)
+
+ // Copy message buffer to local variable, then clear message buffer
+ memory.copy(changetype<usize>(verify_msg), changetype<usize>(MESSAGE_BUFFER), mlen)
+ MESSAGE_BUFFER.fill(0)
- const msg = changetype<StaticArray<u8>>(MESSAGE_BUFFER)
+ // Verify, then clear local input
+ const verified = crypto_verify(verify_sig, verify_msg, mlen, verify_pub)
+ verify_msg.fill(0)
+ verify_pub.fill(0)
+ verify_sig.fill(0)
- memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
- return crypto_verify(sig, msg, mlen, pub)
+ // Output buffer not used, so just return
+ return verified
}
type Exports = {
exports: {
- derive: () => void,
- sign: (mlen: number) => void,
- verify: (mlen: number) => number,
- getOutputPointer: () => number,
- getInputPointer: () => number,
- getMessagePointer: () => number,
+ derive: () => void
+ sign: (mlen: number) => void
+ verify: (mlen: number) => number
+ getInputPointer: () => number
+ getMessagePointer: () => number
+ getOutputPointer: () => number
memory: WebAssembly.Memory
}
}
col >>>= 0
const message = `Nano25519WasmError: ${getString(msg)}, ${getString(file)}, row ${row}, col ${col}`
throw new Error(message)
- },
- memory: new WebAssembly.Memory({ initial: 1, maximum: 1 })
+ }
}
}) as Exports
}
}
-function clear (buffer: Uint8Array): void {
+function clear (memory: Uint8Array): void {
let inPtr = exports.getInputPointer()
let outPtr = exports.getOutputPointer()
- buffer.fill(0, inPtr, inPtr + 96)
- buffer.fill(0, outPtr, outPtr + 64)
+ memory.fill(0, inPtr, inPtr + 96)
+ memory.fill(0, outPtr, outPtr + 64)
}
function isBytes (a: unknown): a is Uint8Array<ArrayBuffer> {