{"record":{"id":"91d15e2d004d171f","repo":"diem/diem","slug":"invalid-public-key-bytes","errorCode":null,"errorMessage":"Invalid public key bytes","messagePattern":"Invalid public key bytes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"language/move-prover/interpreter/crypto/src/lib.rs","lineNumber":63,"sourceCode":"    }\n\n    let mut bits = [0u8; ED25519_PUBLIC_KEY_LENGTH];\n    bits.copy_from_slice(&bytes[..ED25519_PUBLIC_KEY_LENGTH]);\n\n    let compressed = curve25519_dalek::edwards::CompressedEdwardsY(bits);\n    let point = match compressed.decompress() {\n        None => return false,\n        Some(point) => point,\n    };\n\n    // Check if the point lies on a small subgroup. This is required\n    // when using curves with a small cofactor (in ed25519, cofactor = 8).\n    !point.is_small_order()\n}\n\npub fn ed25519_deserialize_public_key(bytes: &[u8]) -> Result<Ed25519PublicKey> {\n    if !validate_public_key(bytes) {\n        bail!(\"Invalid public key bytes\");\n    }\n    Ok(Ed25519PublicKey::from_bytes(bytes)?)\n}\n\nfn validate_signature(bytes: &[u8]) -> bool {\n    if bytes.len() != ED25519_SIGNATURE_LENGTH {\n        return false;\n    }\n    for i in (0..32).rev() {\n        match bytes[32 + i].cmp(&L[i]) {\n            Ordering::Less => return true,\n            Ordering::Greater => return false,\n            _ => (),\n        }\n    }\n    // As this stage S == L which implies a non canonical S.\n    false\n}","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/diem/diem/blob/fc4714a8ea273b6efe8b13dbce72ea60aad9a16c/language/move-prover/interpreter/crypto/src/lib.rs#L45-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// Move: before\nlet pk = ed25519_deserialize_public_key(key_bytes);\n// after\nassert!(length(key_bytes) == 32, E_INVALID_KEY);\nlet pk = ed25519_deserialize_public_key(key_bytes);","handlingStrategy":"validation","validationCode":"// Move\nassert!(length(key_bytes) == 32, E_INVALID_KEY);","typeGuard":"fn is_valid_key_len(bytes: &[u8]) -> bool {\n    bytes.len() == 32 && bytes.iter().any(|&b| b != 0)\n}","tryCatchPattern":null,"preventionTips":["Check key length before native crypto calls","Reject all-zero/degenerate keys at the application boundary","Use vetted serialization for keys end to end"],"tags":["crypto","ed25519","public-key","validation"],"backgroundTag":"invalid-public-key-bytes","analyzedSha":"fc4714a8ea273b6efe8b13dbce72ea60aad9a16c","analyzedAt":"2026-09-04T21:07:05.890Z","contentChangedAt":"2026-09-04T21:07:05.890Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}