*"is this a sound Ed25519 signature"*. Do not "fix" one to match the other.
`crypto_verify_decodepubkey` returns **`ge_p3 | null`**, and
-`crypto_verify_relaxed(s, M, A, pub)` takes that `A` as a parameter. Skipping the
+`crypto_verify_donna(s, M, A, pub)` takes that `A` as a parameter. Skipping the
key check is therefore a **compile error**, not a silent wrong answer — it used
to reuse a module-level `A` left behind by the previous call, so calling it cold
verified against whichever key ran last. Keep the value threaded through the
-signature rather than reintroducing shared state. `crypto_verify_strict` does its
+signature rather than reintroducing shared state. `crypto_verify_sodium` does its
own key handling inline.
**The cap is a latency decision, not a throughput one.** `(1 - 1/n)` is 96.9% at
}
/**
- * Verify signature `s` was made by signing block hash `M` using public key
+ * Verify signature `sig` was made by signing block hash `M` using public key
* `pub`. Based on ed25519-donna to align with nano-node. Differences from
- * `crypto_verify_strict`:
+ * `crypto_verify_sodium`:
*
* - S < 2²⁵³, instead of S < L
* - Skip canonical and small-order checks on public key
* to `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>, A: ge_p3, pub: StaticArray<u8>): i32 {
+export function crypto_verify_donna (sig: StaticArray<u8>, M: StaticArray<u8>, A: ge_p3, pub: StaticArray<u8>): i32 {
// fail if private scalar `S` is out of range (`2²⁵³ ≤ S`)
- if ((s[63] & 224) != 0) return -1
+ if ((sig[63] & 224) != 0) return -1
- memory.copy(changetype<usize>(S), changetype<usize>(s) + 32, 32)
+ memory.copy(changetype<usize>(S), changetype<usize>(sig) + 32, 32)
// signature is nonce point R and scalar S (R || S)
// data to hash is nonce point R, public key A, and message M
// from parameter arguments: R = s[0,32], A = pk, M = m
// R, S, A, and M are all 32-byte values in this implementation
- blake2b.init().update(s, 32).update(pub, KEY_BYTELENGTH).update(M, BLOCKHASH_BYTELENGTH).digest(h)
+ blake2b.init().update(sig, 32).update(pub, KEY_BYTELENGTH).update(M, BLOCKHASH_BYTELENGTH).digest(h)
sc_reduce(h)
ge_double_scalarmult_vartime_to_p3(sb_ah, h, changetype<ge_p3>(A), S)
ge_p3_tobytes(check_r, sb_ah)
- return equalbytes(s, check_r, 32) - 1
+ return equalbytes(sig, check_r, 32) - 1
}
/**
- * Verify signature `s` was made by signing message `M` using public key `pub`.
+ * Verify signature `sig` was made by signing message `M` using public key
+ * `pub`.
*
- * Unlike `crypto_verify_relaxed`, this function is intended for single-use
+ * Unlike `crypto_verify_donna`, this function is intended for single-use
* verifications and thus can compute and set `A` itself.
* @returns -1 if signature fails to verify, else return 0 if signature is good
*/
-export function crypto_verify_strict (s: StaticArray<u8>, M: StaticArray<u8>, mlen: i32, pub: StaticArray<u8>): i32 {
+export function crypto_verify_sodium (sig: 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
if (ge_has_small_order(A) != 0) return -1
// fail if private scalar `S` is non-canonical (`L ≤ S`)
- memory.copy(changetype<usize>(S), changetype<usize>(s) + 32, 32)
+ memory.copy(changetype<usize>(S), changetype<usize>(sig) + 32, 32)
if (!sc_is_canonical(S)) return -1
- if (ge_frombytes(expected_r, s) != 0) return -1
+ if (ge_frombytes(expected_r, sig) != 0) return -1
if (ge_has_small_order(expected_r) != 0) return -1
// signature is nonce point R and scalar S (R || S)
// data to hash is nonce point R, public key A, and message M
// from parameter arguments: R = s[0,32], A = pk, M = m
// R, S, A, and M are all 32-byte values in this implementation
- blake2b.init().update(s, 32).update(pub, 32).update(M, mlen).digest(h)
+ blake2b.init().update(sig, 32).update(pub, 32).update(M, mlen).digest(h)
sc_reduce(h)
ge_double_scalarmult_vartime_to_p3(sb_ah, h, A, S)
import { crypto_derive } from './crypto_derive'
import { crypto_sign } from './crypto_sign'
-import { crypto_verify_decodepubkey, crypto_verify_relaxed, crypto_verify_strict } from './crypto_verify'
+import { crypto_verify_decodepubkey, crypto_verify_donna, crypto_verify_sodium } from './crypto_verify'
import { errors } from './errors'
import './tests'
INPUT_SIG.fill(0)
// Verify message from buffer, then write result to output buffer
- OUTPUT_VERIFY[0] = u8(crypto_verify_strict(sig, INPUT_MSG, mlen, pub))
+ OUTPUT_VERIFY[0] = u8(crypto_verify_sodium(sig, INPUT_MSG, mlen, pub))
// Clear message buffer and input locals
INPUT_MSG.fill(0)
memory.copy(changetype<usize>(h), ptr + SIGNATURE_BYTELENGTH, BLOCKHASH_BYTELENGTH)
// Verify hash and signature, then write result to output buffer
- OUTPUT_VERIFY[i] = u8(crypto_verify_relaxed(sig, h, A, pub))
+ OUTPUT_VERIFY[i] = u8(crypto_verify_donna(sig, h, A, pub))
}
}