// crypto_hash function\r
const blake2b = new Blake2b()\r
\r
+/**\r
+ * Clears the 3 least significant bits to guarantee multiple of 8 and prevent\r
+ * small-subgroup attacks based on Curve25519's cofactor of 8. Also sets bit 254\r
+ * and clears bit 255 to guarantee a fixed bit length for constant time\r
+ * performance.\r
+ * @param k 32-byte scalar\r
+ */\r
//@ts-expect-error\r
@inline\r
function clamp (k: StaticArray<u8>): void {\r
k[31] |= 64\r
}\r
\r
-const crypto_derive_pk: StaticArray<u8> = new StaticArray<u8>(PUBLICKEY_BYTES)\r
-function crypto_derive (sk: StaticArray<u8>, seed: StaticArray<u8>): void {\r
- const pk = crypto_derive_pk\r
- blake2b.init().update(changetype<usize>(seed), 32).digest(sk)\r
- clamp(sk)\r
-\r
- ge_scalarmult_base_tobytes(pk, sk)\r
- memory.copy(changetype<usize>(sk), changetype<usize>(pk), PUBLICKEY_BYTES)\r
+const crypto_derive_a: StaticArray<u8> = new StaticArray<u8>(PRIVATEKEY_BYTES)\r
+const crypto_derive_az: StaticArray<u8> = new StaticArray<u8>(SECRETKEY_BYTES)\r
+/**\r
+ * Hash seed to 32-byte scalar `a`, clamp it, then point-multiply it by the\r
+ * Ed25519 base point.\r
+ * @param pk 32-byte output buffer for the compressed public key\r
+ * @param seed 32-byte input buffer for the securely-random secret seed value\r
+ */\r
+function crypto_derive (pk: StaticArray<u8>, seed: StaticArray<u8>): void {\r
+ const a = crypto_derive_a\r
+ const az = crypto_derive_az\r
+ blake2b.init().update(changetype<usize>(seed), 32).digest(az)\r
+ memory.copy(changetype<usize>(a), changetype<usize>(az), 32)\r
+ az.fill(0)\r
+ clamp(a)\r
+ ge_scalarmult_base_tobytes(pk, a)\r
+ a.fill(0)\r
}\r
\r
const crypto_sign_az = new StaticArray<u8>(64)\r