Skip to content

Commit 4207ed3

Browse files
committed
chore: assert top bit isn't set
In the xHD lib, the signing function uses [crypto_scalarmult_ed25519_base_noclamp](https://github.com/algorandfoundation/xHD-Wallet-API-ts/blob/96e7a4be6bca67a4f77252206811f7676e59e5ec/src/x.hd.wallet.api.crypto.ts#L144-L144) to get the public key which [clears the top bit](https://github.com/algorandfoundation/xHD-Wallet-API-ts/blob/9849fb3e90cecfb6348e188ff445b55806bfde00/src/sumo.facade.ts#L106-L106). Then for the signing, the [raw scalar](https://github.com/algorandfoundation/xHD-Wallet-API-ts/blob/96e7a4be6bca67a4f77252206811f7676e59e5ec/src/x.hd.wallet.api.crypto.ts#L156-L156) is used without clearing the top bit. Since this is not an exported function and the keys used are always from the known derivation function (which ensure the top bit is clear), then this is not an issue. In AlgoKit, however, we have no guarantees about where the scalar comes from. As such, it's possible for someone to pass a scalar that does not have the top bit cleared. The two options are to either clear it automatically or error, but since a scalar without the top bit cleared is invalid ed255519 scalar it seems preferable to just throw an error.
1 parent d185518 commit 4207ed3

File tree

1 file changed

+6
-2
lines changed

1 file changed

+6
-2
lines changed

packages/crypto/src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ function rawSign(extendedSecretKey: Uint8Array, data: Uint8Array): Uint8Array {
6767

6868
function rawPubkey(extendedSecretKey: Uint8Array): Uint8Array {
6969
const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32))
70-
const clearedTopBitScalar = scalar & ((1n << 255n) - 1n)
71-
const reducedScalar = mod(clearedTopBitScalar, ed25519.Point.Fn.ORDER)
70+
if ((scalar & (1n << 255n)) !== 0n) {
71+
throw new Error(
72+
'Invalid HD-expanded Ed25519 secret scalar: most-significant bit (bit 255) of the 32-byte scalar must be 0 for rawSign/rawPubkey inputs.',
73+
)
74+
}
75+
const reducedScalar = mod(scalar, ed25519.Point.Fn.ORDER)
7276

7377
// pubKey = scalar * G
7478
const publicKey = ed25519.Point.BASE.multiply(reducedScalar)

0 commit comments

Comments
 (0)