Сообщение об ошибке
invalid raw signature length
Также выводится как
- invalid raw signature length (argument="signature", value="0x…", code=INVALID_ARGUMENT, version=6.17.0)
- TypeError: invalid raw signature length
`err.shortMessage` содержит «invalid raw signature length»; `err.message` добавляет аргумент, значение и версию ethers. Ошибка имеет тип `TypeError` с `code: "INVALID_ARGUMENT"`.
ethers v6 (JavaScript) — Signature.from() inside verifyMessage / verifyTypedData / recoverAddress
Что это означает
ethers попытался прочитать байты подписи как подпись ECDSA, чтобы восстановить адрес, но длина не подходит ни под одну известную ему форму: 65 байт (r‖s‖v) или 64 байта (компактная форма EIP-2098). Восстановление даже не начиналось. Обычно это вообще подпись другого вида: подпись смарт-аккаунта, которую нужно проверять в блокчейне, или подпись в кодировке DER от сервиса управления ключами.
Почему это происходит
Подпись кошелька на смарт-контракте
частоSafe, Coinbase Smart Wallet, Argent и другие аккаунты ERC-4337 возвращают подписи, которые может проверить только контракт аккаунта (ERC-1271), причём для ещё не развёрнутых аккаунтов они часто обёрнуты по ERC-6492. Такие подписи длиной в сотни байт, и проверить их через `verifyMessage` нельзя.
Подпись DER от AWS KMS или Google Cloud KMS
частоКлючи `ECC_SECG_P256K1` в AWS KMS и `EC_SIGN_SECP256K1_SHA256` в Google Cloud KMS возвращают ASN.1 DER (70–72 байта) без идентификатора восстановления. Сначала подпись нужно преобразовать в r‖s‖v.
Подпись обрезана или закодирована дважды
иногдаПодпись, обрезанная в столбце базы данных, hex от hex-строки или значение, потерявшее последний байт, когда `v` хранили отдельно.
Как исправить
- 1.
Проверяйте подписи смарт-аккаунтов в блокчейне
Вызовите `isValidSignature` (ERC-1271) у аккаунта или используйте библиотеку с поддержкой ERC-6492 для контрфактических аккаунтов (например, `verifyMessage` из viem с публичным клиентом).
js import { Contract, hashMessage, JsonRpcProvider } from "ethers"; // Smart accounts (Safe, Coinbase Smart Wallet, ERC-4337 accounts) are verified on-chain (ERC-1271). const provider = new JsonRpcProvider(process.env.RPC_URL); const account = new Contract(address, ["function isValidSignature(bytes32,bytes) view returns (bytes4)"], provider); const magic = await account.isValidSignature(hashMessage(message), signature); const valid = magic === "0x1626ba7e"; - 2.
Преобразуйте DER в r‖s‖v
Разберите r и s, нормализуйте s в нижнюю половину порядка группы (Ethereum отклоняет значения high-S) и попробуйте оба бита восстановления, чтобы найти тот, который даёт ожидаемый адрес.
js import { Signature, recoverAddress, hashMessage, toBeHex } from "ethers"; import { secp256k1 } from "@noble/curves/secp256k1.js"; // @noble/curves v2 const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n; // secp256k1 order // KMS/HSM: parse DER, move s to the lower half (Ethereum rejects high-s), then find the recovery bit. function derToEthSignature(derBytes, digest, expectedAddress) { const { r, s } = secp256k1.Signature.fromBytes(derBytes, "der"); const lowS = s > N / 2n ? N - s : s; for (const yParity of [0, 1]) { const candidate = Signature.from({ r: toBeHex(r, 32), s: toBeHex(lowS, 32), yParity }); if (recoverAddress(digest, candidate) === expectedAddress) return candidate.serialized; // 65 bytes } throw new Error("signature does not belong to " + expectedAddress); } const signature = derToEthSignature(kmsDer, hashMessage(message), kmsAddress);