Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare an ascii string with a uint8 array in Solidity?

I have a uint8 array containing ASCII codes for characters and a string variable, and I wish to make a comparison between them. For example:

uint8[3] memory foo = [98, 97, 122]; // baz
string memory bar = "baz";

bool result = keccak256(abi.encodePacked(foo)) == keccak256(abi.encodePacked(bytes(bar))); // false

Here I want the comparison to succeed, but it's a failure because encodePacked will keep the padding of all the uint8 elements in the array when encoding it.

How can I do it instead?

like image 211
Elf Avatar asked Dec 20 '25 16:12

Elf


1 Answers

You are currently comparing encoded value abi.encodePacked(foo)) to hashed value keccak256(abi.encodePacked(bytes(bar)), which would never equal.


The uint8 fixed-size array is stored in memory in three separate slots - one for each item - and each of the items is ordered right to left (little endian).

0x
0000000000000000000000000000000000000000000000000000000000000062
0000000000000000000000000000000000000000000000000000000000000061
000000000000000000000000000000000000000000000000000000000000007a

But the string literal is stored as a dynamic-size byte array ordered left to right (big endian):

0x
0000000000000000000000000000000000000000000000000000000000000020 # pointer
0000000000000000000000000000000000000000000000000000000000000003 # length
62617a0000000000000000000000000000000000000000000000000000000000 # value

So because the actual data is stored differently, you cannot perform a simple byte comparison of both arrays.

You can, however, loop through all items of the array and compare each item separately.

pragma solidity ^0.8;

contract MyContract {
    function compare() external pure returns (bool) {
        uint8[3] memory foo = [98, 97, 122]; // baz
        string memory bar = "baz";

        // typecast the `string` to `bytes` dynamic-length array
        // so that you can use its `.length` member property
        // and access its items individually (see `barBytes[i]` below, not possible with `bar[i]`)
        bytes memory barBytes = bytes(bar);

        // prevent accessing out-of-bounds index in the following loop
        // as well as false positive if `foo` contains just the beginning of `bar` but not the whole string
        if (foo.length != barBytes.length) {
            return false;
        }

        // loop through each item of `foo`
        for (uint i; i < foo.length; i++) {
            uint8 barItemDecimal = uint8(barBytes[i]);
            // and compare it to each decimal value of `bar` character
            if (foo[i] != barItemDecimal) {
                return false;
            }
        }

        // all items have equal values
        return true;
    }
}
like image 104
Petr Hejda Avatar answered Dec 24 '25 12:12

Petr Hejda



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!