BlockchainSolidity5 min readUpdated

abi.encodePacked of uint256 vs bytes32: 32-Byte Big-Endian Semantics

By Mudassir Khan — Agentic AI Consultant & AI Systems Architect, Islamabad, Pakistan

Cover illustration for: abi.encodePacked of uint256 vs bytes32: 32-Byte Big-Endian Semantics

Quick answer

Does abi.encodePacked of a uint256 produce the same bytes as bytes32? Yes. abi.encodePacked(uint256 value) writes 32 bytes in big-endian order. abi.encodePacked(bytes32(value)) writes the same 32 bytes. The two calls produce byte-identical output because bytes32 and uint256 share the same EVM storage layout and abi.encodePacked does not add length prefixes to fixed-width types.

Section 01 · Encoding

What abi.encodePacked actually does

Two encoding functions exist in Solidity. For uint256 and bytes32, their output is identical — but they diverge the moment a dynamic type appears.

Two encoding functions are available in Solidity:

  • abi.encode(...) is the canonical ABI encoder. Fixed-width types pad to 32 bytes; dynamic types get a length-prefix offset. Used by every call(...) and event log.
  • abi.encodePacked(...) is the tight-pack encoder. Each value is written at its own natural byte width with no padding and no length prefix. Used when the developer wants the smallest possible byte sequence — typically for hashing.

For uint256 and bytes32, the natural byte width is identical (32 bytes), so the packed output is identical:

solidity
uint256 x = 0x000000000000000000000000000000000000000000000000000000000000002a; // 42

bytes memory a = abi.encodePacked(x);           // 32 bytes, big-endian
bytes memory b = abi.encodePacked(bytes32(x));  // same 32 bytes
// keccak256(a) == keccak256(b) — always.

This is why uint256 and bytes32 are interchangeable inside hash inputs. They occupy the same slot, big-endian.

Section 02 · Fixed-Width

When the equivalence holds

For any combination of fixed-width types, packed encoding is unambiguous and collision-free.

solidity
keccak256(abi.encodePacked(uint256 a, uint256 b))
// 64 bytes — first 32 are `a`, second 32 are `b`. Deterministic, no collision possible.

uint8, uint16, ..., uint256, int* siblings, address (20 bytes), bytes1 through bytes32, and bool (1 byte) all pack at their natural width with no surprises.

Section 03 · Collision Risk

When the equivalence breaks

The moment a dynamic type appears in the call, packed encoding loses injectivity — and collisions become possible.

solidity
keccak256(abi.encodePacked("ab", "c"));  // packs "abc" (3 bytes)
keccak256(abi.encodePacked("a", "bc"));  // packs "abc" (3 bytes) — same hash

Both calls produce identical hash inputs because abi.encodePacked writes string contents without length prefixes. Two different logical inputs collide to the same hash.

Production exploit pattern

A signature scheme that hashes abi.encodePacked(user, message) is vulnerable to replay if the attacker can manipulate where user ends and message begins. This is the most common audit finding on custom signature validation logic.

This is the production exploit pattern: a signature scheme that hashes abi.encodePacked(user, message) is vulnerable to replay if the attacker can manipulate where user ends and message begins.

Section 04 · Safe Usage

The safe pattern

Three rules cover every safe usage of abi.encodePacked in production.

Three rules cover the safe usage:

  • Use abi.encode, not abi.encodePacked, whenever a dynamic type is involved. abi.encode adds the length prefix and the encoding is unambiguous.
  • Use abi.encodePacked only when every input is fixed-width or when collisions are impossible by construction (for example, you control the input completely and never let user data into the pack).
  • When you need both performance (tight packing) and safety, separate the dynamic parts with a fixed-width delimiter that the attacker cannot inject. For example, abi.encodePacked(user, bytes1(0x00), message) is collision-resistant if user cannot contain a null byte.

Pair this with the keccak256 hash generator tool and the ABI encoder decoder to test your encoding decisions interactively before committing them to a deployed contract.

Section 05 · Context

Why this query shows up in search

The unusually long query phrasing is a signal: the developer is mid-implementation and testing an assumption.

Developers pasting solidity abi.encodepacked uint256 bytes32 encoding 32 bytes big endian into Google are usually verifying a hash input mid-implementation. The query phrasing is unusually long because the developer is testing whether the two encodings are equivalent — they typed every fact they thought might matter into the search bar.

The short answer is: yes, equivalent for these two specific types. The longer answer (the one that matters for production) is: stop using abi.encodePacked with any dynamic input.

FAQ

Frequently asked questions

Common follow-up questions about abi.encodePacked encoding semantics in Solidity.

Is abi.encodePacked(uint256) the same as casting to bytes32 manually?

For the byte output, yes. Both produce a 32-byte big-endian sequence. The cast bytes32(uint256Value) does not change the bit pattern; it just reinterprets the storage slot.

Does endianness matter on the EVM?

The EVM is big-endian for stack and memory. uint256 is stored big-endian, so abi.encodePacked(uint256) writes the most-significant byte first. This matches Ethereum's wire format conventions and matters when interoperating with external systems that use little-endian (Solana, x86).

Why does OpenZeppelin's ECDSA.toEthSignedMessageHash use abi.encodePacked?

Because the inputs are all fixed-width: the prefix string is a constant of known length, and the hash is bytes32. No dynamic input means no collision risk.

When should I use abi.encode instead?

Whenever the function accepts arbitrary user data, especially string or bytes. The length prefix overhead is small (roughly 32 bytes per dynamic input) and the safety gain is large.

Written by Mudassir Khan

Agentic AI consultant and AI systems architect based in Islamabad, Pakistan. CEO of Cube A Cloud. 38+ agentic AI launches delivered for global founders and CTOs.

View Blockchain Development serviceSee ChainTrust Compliance Engine case study

Related service

Blockchain Development

See scope & pricing →

Related case study

ChainTrust Compliance Engine

Read case study →

More on this topic

Need an AI systems architect?

Book a 30-minute architecture call. I will sketch the high-level design for your use case and give you an honest view of the trade-offs.

Book a strategy call →