const S = new StaticArray<u8>(32)
/**
- * Verify signature `s` was made by signing message `M` using public key `pub`.
- * @returns -1 if signature fails to verify, else return 0 if signature is good
+ * Verify public key `pub` is canonical, non-malleable, and correct.
+ * @returns -1 if public key fails to verify, else return 0 if public key is good
*/
-export function crypto_verify_strict (s: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
+export function crypto_verify_pubkey (pub: StaticArray<u8>): i32 {
// fail if public key `k` is non-canonical (`p = 2²⁵⁵-19 ≤ k`)
if (!ge_is_canonical(pub)) return -1
+ if (ge_frombytes_negate_vartime(A, pub) != 0) return -1
+ if (ge_has_small_order(A) != 0) return -1
+
+ return 0
+}
+
+/**
+ * Verify signature `s` was made by signing message `M` using public key `pub`.
+ *
+ * IMPORTANT: Callers MUST call `crypto_verify_pubkey` first in order to set `A`
+ * for the scalar multiplication step before checking `sB = R + hA`.
+ * @returns -1 if signature fails to verify, else return 0 if signature is good
+ */
+export function crypto_verify_relaxed (s: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
+
// fail if private scalar `S` is non-canonical (`L ≤ S`)
memory.copy(changetype<usize>(S), changetype<usize>(s) + 32, 32)
if (!sc_is_canonical(S)) return -1
- if (ge_frombytes_negate_vartime(A, pub) != 0) return -1
- if (ge_has_small_order(A) != 0) return -1
-
if (ge_frombytes(expected_r, s) != 0) return -1
if (ge_has_small_order(expected_r) != 0) return -1
/**
* Verify signature `s` was made by signing message `M` using public key `pub`.
+ *
+ * Unlike `crypto_verify_relaxed`, this function is intended for single-use
+ * verifications and thus can compute and set `A` by calling
+ * `crypto_verify_pubkey` itself.
* @returns -1 if signature fails to verify, else return 0 if signature is good
*/
-export function crypto_verify_relaxed (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
+export function crypto_verify_strict (s: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
+ if (crypto_verify_pubkey(pub) != 0) return -1
// fail if private scalar `S` is non-canonical (`L ≤ S`)
memory.copy(changetype<usize>(S), changetype<usize>(s) + 32, 32)
if (!sc_is_canonical(S)) return -1
- if (ge_frombytes_negate_vartime(A, pub) != 0) return -1
- if (ge_has_small_order(A) != 0) return -1
-
if (ge_frombytes(expected_r, s) != 0) return -1
if (ge_has_small_order(expected_r) != 0) return -1
import { crypto_derive } from './crypto_derive'
import { crypto_sign } from './crypto_sign'
-import { crypto_verify_relaxed, crypto_verify_strict } from './crypto_verify'
+import { crypto_verify_pubkey, crypto_verify_relaxed, crypto_verify_strict } from './crypto_verify'
export const BLOCKHASH_BYTELENGTH: i32 = 32
export const KEY_BYTELENGTH: i32 = 32
memory.copy(changetype<usize>(verify_blocks_pub), changetype<usize>(PUB_BUFFER), KEY_BYTELENGTH)
PUB_BUFFER.fill(0)
+ // Verify public key, then clear local input
+ const validPubkey = crypto_verify_pubkey(verify_blocks_pub)
+ verify_blocks_pub.fill(0)
+
// Iterate over block hash/signature pairs
for (let i = 0; i < count; i++) {
// Copy message buffer to local block hash/signature buffers
memory.copy(changetype<usize>(verify_blocks_sig), changetype<usize>(MESSAGE_BUFFER) + BLOCKHASH_BYTELENGTH + (96 * i), SIGNATURE_BYTELENGTH)
// Verify hash and signature, then copy local result to output buffer
- const verified = crypto_verify_relaxed(verify_blocks_sig, verify_blocks_msg, BLOCKHASH_BYTELENGTH, verify_blocks_pub)
- verify_blocks_out[i] = u8(verified)
+ verify_blocks_out[i] = u8(validPubkey | crypto_verify_relaxed(verify_blocks_sig, verify_blocks_msg, BLOCKHASH_BYTELENGTH, verify_blocks_pub))
}
// Clear local input