// crypto_hash function
const blake2b = new Blake2b()
-const crypto_derive_h: StaticArray<u8> = new StaticArray<u8>(SECRETKEY_BYTES)
-const crypto_derive_s: StaticArray<u8> = new StaticArray<u8>(PRIVATEKEY_BYTES)
+// algorithm variables
+const h: StaticArray<u8> = new StaticArray<u8>(SECRETKEY_BYTES)
+const s: StaticArray<u8> = new StaticArray<u8>(PRIVATEKEY_BYTES)
+
/**
* Hash seed to 32-byte scalar `a`, clamp it, then point-multiply it by the
* Ed25519 base point. The Nano specification uses BLAKE2b as the hash function
* @param key 32-byte private key "seed" of cryptographically secure random data
*/
export function crypto_derive (A: StaticArray<u8>, key: StaticArray<u8>): void {
- const h = crypto_derive_h
- const s = crypto_derive_s
+
// Hash private key to 64-byte buffer `h`
blake2b.init().update(key, 32).digest(h)
+
// Keep only the lower 32 bytes as secret scalar `s` for deriving public key
memory.copy(changetype<usize>(s), changetype<usize>(h), 32)
h.fill(0)
+
// Clear lowest three bits and highest bit, then set second highest bit
clamp(s)
+
// Perform fixed-base scalar multiplication `[s]B`, output to public key `A`
ge_scalarmult_base_tobytes(A, s)
s.fill(0)
// crypto_hash function
const blake2b = new Blake2b()
-const crypto_sign_h = new StaticArray<u8>(64)
-const crypto_sign_s = new StaticArray<u8>(32)
-const crypto_sign_prefix = new StaticArray<u8>(32)
-const crypto_sign_r = new StaticArray<u8>(64)
-const crypto_sign_R = new StaticArray<u8>(64)
-const crypto_sign_k = new StaticArray<u8>(64)
-const crypto_sign_S = new StaticArray<u8>(64)
+// algorithm variables
+const h = new StaticArray<u8>(64)
+const s = new StaticArray<u8>(32)
+const prefix = new StaticArray<u8>(32)
+const r = new StaticArray<u8>(64)
+const R = new StaticArray<u8>(64)
+const k = new StaticArray<u8>(64)
+const S = new StaticArray<u8>(64)
/**
* Sign a message with a secret key. The Nano specification uses BLAKE2b as the
* hash function instead of SHA-512 specified by RFC 8032.
* @param {StaticArray<u8>} A 32-byte public key from input buffer
*/
export function crypto_sign (RS: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, key: StaticArray<u8>, A: StaticArray<u8>): void {
- const h = crypto_sign_h
- const s = crypto_sign_s
- const prefix = crypto_sign_prefix
- const r = crypto_sign_r
- const R = crypto_sign_R
- const k = crypto_sign_k
- const S = crypto_sign_S
// Hash private key to `h`
blake2b.init().update(key, PRIVATEKEY_BYTES).digest(h)
// crypto_hash function
const blake2b = new Blake2b()
-const crypto_verify_h = new StaticArray<u8>(64)
-const crypto_verify_check = new ge_p3()
-const crypto_verify_expected_r = new ge_p3()
-const crypto_verify_A = new ge_p3()
-const crypto_verify_sb_ah = new ge_p3()
-const crypto_verify_S = new StaticArray<u8>(32)
+// algorithm variables
+const h = new StaticArray<u8>(64)
+const check = new ge_p3()
+const expected_r = new ge_p3()
+const A = new ge_p3()
+const sb_ah = new ge_p3()
+const S = new StaticArray<u8>(32)
+
/**
* Verify signature `s` was made by signing message `m` using public key `pk`.
* @returns -1 if signature fails to verify, else return 0 if signature is good
*/
-export function crypto_verify (s: StaticArray<u8>, m: usize, mlen: i32, pub: StaticArray<u8>): i32 {
- const M = changetype<StaticArray<u8>>(m)
- const h = crypto_verify_h
- const check = crypto_verify_check
- const expected_r = crypto_verify_expected_r
- const A = crypto_verify_A
- const sb_ah = crypto_verify_sb_ah
- const S = crypto_verify_S
+export function crypto_verify (s: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
// fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 <= k`)
if (!ge_is_canonical(pub)) return -1
return MESSAGE_BUFFER
}
+const derive_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
+const derive_prv = new StaticArray<u8>(PRIVATEKEY_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:
*
* - `[0,31]: private key`
- * - `[32,63]: public key`
*
* The public key is written to the output buffer.
*/
export function derive (): void {
- const pub = changetype<StaticArray<u8>>(OUTPUT_BUFFER)
- const prv = changetype<StaticArray<u8>>(INPUT_BUFFER)
- memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
- crypto_derive(pub, prv)
+ const pub = derive_pub
+ const prv = derive_prv
+
+ memory.copy(changetype<usize>(prv), INPUT_BUFFER, PRIVATEKEY_BYTES)
memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES)
+
+ crypto_derive(pub, prv)
+ memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
+ memory.copy(OUTPUT_BUFFER, changetype<usize>(pub), PUBLICKEY_BYTES)
}
-const sign_s = new StaticArray<u8>(SIGNATURE_BYTES)
+const sign_sig = new StaticArray<u8>(SIGNATURE_BYTES)
const sign_prv = new StaticArray<u8>(PRIVATEKEY_BYTES)
const sign_pub = new StaticArray<u8>(PUBLICKEY_BYTES)
/**
*/
export function sign (mlen: i32): void {
if (mlen < 0 || mlen > 32768) throw new Error()
- const s = sign_s
+ const sig = sign_sig
const prv = sign_prv
const pub = sign_pub
memory.copy(changetype<usize>(pub), INPUT_BUFFER + PRIVATEKEY_BYTES, PUBLICKEY_BYTES)
memory.fill(INPUT_BUFFER, 0, INPUT_BUFFER_BYTES)
- const m = changetype<StaticArray<u8>>(MESSAGE_BUFFER)
+ const msg = changetype<StaticArray<u8>>(MESSAGE_BUFFER)
+ crypto_sign(sig, msg, mlen, prv, pub)
memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
- crypto_sign(s, m, mlen, prv, pub)
- memory.copy(OUTPUT_BUFFER, changetype<usize>(s), SIGNATURE_BYTES)
+ memory.copy(OUTPUT_BUFFER, changetype<usize>(sig), SIGNATURE_BYTES)
}
-const verify_s = new StaticArray<u8>(SIGNATURE_BYTES)
-const verify_k = new StaticArray<u8>(PUBLICKEY_BYTES)
+const verify_sig = new StaticArray<u8>(SIGNATURE_BYTES)
+const verify_pub = new StaticArray<u8>(PUBLICKEY_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 s = verify_s
- const m = MESSAGE_BUFFER
- const k = verify_k
+ const sig = verify_sig
+ const pub = verify_pub
- memory.copy(changetype<usize>(s), INPUT_BUFFER, SIGNATURE_BYTES)
- memory.copy(changetype<usize>(k), INPUT_BUFFER + SIGNATURE_BYTES, PUBLICKEY_BYTES)
+ 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)
- return crypto_verify(s, m, mlen, k)
+
+ const msg = changetype<StaticArray<u8>>(MESSAGE_BUFFER)
+
+ memory.fill(OUTPUT_BUFFER, 0, OUTPUT_BUFFER_BYTES)
+ return crypto_verify(sig, msg, mlen, pub)
}