diem/diem · error
Invalid public key bytes
Error message
Invalid public key bytes
What it means
The Move interpreter's crypto intrinsics reject public keys that fail validation before constructing an Ed25519PublicKey. validate_public_key checks the 32-byte length and that the Edwards point is not small-order (malleability protection for ed25519's cofactor of 8), so this error means the bytes are not a valid, non-malleable ed25519 public key.
Source
Thrown at language/move-prover/interpreter/crypto/src/lib.rs:63
}
let mut bits = [0u8; ED25519_PUBLIC_KEY_LENGTH];
bits.copy_from_slice(&bytes[..ED25519_PUBLIC_KEY_LENGTH]);
let compressed = curve25519_dalek::edwards::CompressedEdwardsY(bits);
let point = match compressed.decompress() {
None => return false,
Some(point) => point,
};
// Check if the point lies on a small subgroup. This is required
// when using curves with a small cofactor (in ed25519, cofactor = 8).
!point.is_small_order()
}
pub fn ed25519_deserialize_public_key(bytes: &[u8]) -> Result<Ed25519PublicKey> {
if !validate_public_key(bytes) {
bail!("Invalid public key bytes");
}
Ok(Ed25519PublicKey::from_bytes(bytes)?)
}
fn validate_signature(bytes: &[u8]) -> bool {
if bytes.len() != ED25519_SIGNATURE_LENGTH {
return false;
}
for i in (0..32).rev() {
match bytes[32 + i].cmp(&L[i]) {
Ordering::Less => return true,
Ordering::Greater => return false,
_ => (),
}
}
// As this stage S == L which implies a non canonical S.
false
}View on GitHub (pinned to fc4714a8ea)
Solutions
- Validate key bytes are exactly 32 bytes before calling the native
- Reject degenerate/small-order keys (e.g. all zeros) at the application boundary
- Check serialization/deserialization code for truncation or offset bugs
- In Move code, assert `length(key) == 32` before the native call
Example fix
// Move: before let pk = ed25519_deserialize_public_key(key_bytes); // after assert!(length(key_bytes) == 32, E_INVALID_KEY); let pk = ed25519_deserialize_public_key(key_bytes);
Defensive patterns
Strategy: validation
Validate before calling
// Move assert!(length(key_bytes) == 32, E_INVALID_KEY);
Type guard
fn is_valid_key_len(bytes: &[u8]) -> bool {
bytes.len() == 32 && bytes.iter().any(|&b| b != 0)
} Prevention
- Check key length before native crypto calls
- Reject all-zero/degenerate keys at the application boundary
- Use vetted serialization for keys end to end
When it happens
Trigger: Calling native `ed25519_deserialize_public_key` (via native_signature_ed25519_validate_pubkey or native_signature_ed25519_signature_verification) with bytes of the wrong length or encoding a small-order/degenerate curve point.
Common situations: Truncated or padded keys from bad serialization, all-zero or degenerate keys passed by malicious or buggy Move code, or keys from a non-standard ed25519 implementation.
Related errors
- Invalid signature bytes
- {:?}
- Malleable public key
- Malleable signature
- Unable to decrypt address for account {0}: {1}
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/91d15e2d004d171f.
Report an issue: GitHub.