From: Chris Duncan Date: Sat, 15 Aug 2026 19:29:13 +0000 (-0700) Subject: Discard nonce prefix `z` as sensitive material unnecessary for public key derivation... X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=99604f16859f7d5c59d45d05425851ca52d9d5f1;p=nano25519.git Discard nonce prefix `z` as sensitive material unnecessary for public key derivation. Document reason for clamping scalar. --- diff --git a/src/assembly/index.ts b/src/assembly/index.ts index 549d116..be6705e 100644 --- a/src/assembly/index.ts +++ b/src/assembly/index.ts @@ -21,6 +21,13 @@ const MESSAGE_BUFFER = memory.data(32768) // crypto_hash function const blake2b = new Blake2b() +/** + * Clears the 3 least significant bits to guarantee multiple of 8 and prevent + * small-subgroup attacks based on Curve25519's cofactor of 8. Also sets bit 254 + * and clears bit 255 to guarantee a fixed bit length for constant time + * performance. + * @param k 32-byte scalar + */ //@ts-expect-error @inline function clamp (k: StaticArray): void { @@ -29,14 +36,23 @@ function clamp (k: StaticArray): void { k[31] |= 64 } -const crypto_derive_pk: StaticArray = new StaticArray(PUBLICKEY_BYTES) -function crypto_derive (sk: StaticArray, seed: StaticArray): void { - const pk = crypto_derive_pk - blake2b.init().update(changetype(seed), 32).digest(sk) - clamp(sk) - - ge_scalarmult_base_tobytes(pk, sk) - memory.copy(changetype(sk), changetype(pk), PUBLICKEY_BYTES) +const crypto_derive_a: StaticArray = new StaticArray(PRIVATEKEY_BYTES) +const crypto_derive_az: StaticArray = new StaticArray(SECRETKEY_BYTES) +/** + * Hash seed to 32-byte scalar `a`, clamp it, then point-multiply it by the + * Ed25519 base point. + * @param pk 32-byte output buffer for the compressed public key + * @param seed 32-byte input buffer for the securely-random secret seed value + */ +function crypto_derive (pk: StaticArray, seed: StaticArray): void { + const a = crypto_derive_a + const az = crypto_derive_az + blake2b.init().update(changetype(seed), 32).digest(az) + memory.copy(changetype(a), changetype(az), 32) + az.fill(0) + clamp(a) + ge_scalarmult_base_tobytes(pk, a) + a.fill(0) } const crypto_sign_az = new StaticArray(64)