Skip to content

Instantly share code, notes, and snippets.

@thecompez
Last active November 26, 2025 12:56
Show Gist options
  • Select an option

  • Save thecompez/d63b38f8d9900d27719074f481b3a653 to your computer and use it in GitHub Desktop.

Select an option

Save thecompez/d63b38f8d9900d27719074f481b3a653 to your computer and use it in GitHub Desktop.

Revisions

  1. thecompez revised this gist Nov 26, 2025. 1 changed file with 18 additions and 0 deletions.
    18 changes: 18 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -132,3 +132,21 @@ std::string toChecksum(S address) {
    }
    return "0x"+out;
    }


    Usage example:

    import eth.checksum;

    auto main() -> int {
    std::vector<std::string> addresses = {
    "0x...",
    "0x..."
    };

    for(const auto &a : addresses) {
    std::cout << "Checksum: " << toChecksum(a) << "\n";
    }

    return 0;
    }
  2. thecompez created this gist Nov 26, 2025.
    134 changes: 134 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    module;

    import <array>;
    import <string>;
    import <string_view>;
    import <iostream>;
    import <algorithm>;
    import <cctype>;
    import <sstream>;
    import <iomanip>;
    import <concepts>;
    import <vector>;

    export module eth.checksum;

    /* ========================= Utility ========================= */

    constexpr int hexCharToInt(const char c) noexcept {
    if(c >= '0' && c <= '9') return c - '0';
    if(c >= 'a' && c <= 'f') return c - 'a' + 10;
    if(c >= 'A' && c <= 'F') return c - 'A' + 10;
    return 0;
    }

    constexpr char safeToUpper(const char c) noexcept {
    if(c >= 'a' && c <= 'z') return c - 'a' + 'A';
    return c;
    }

    constexpr char safeToLower(const char c) noexcept {
    if(c >= 'A' && c <= 'Z') return c - 'A' + 'a';
    return c;
    }

    /* ========================= Keccak-256 Implementation ========================= */

    export class Keccak256 {
    static constexpr std::array<uint64_t, 24> RC = {
    0x0000000000000001ULL,0x0000000000008082ULL,0x800000000000808aULL,0x8000000080008000ULL,
    0x000000000000808bULL,0x0000000080000001ULL,0x8000000080008081ULL,0x8000000000008009ULL,
    0x000000000000008aULL,0x0000000000000088ULL,0x0000000080008009ULL,0x000000008000000aULL,
    0x000000008000808bULL,0x800000000000008bULL,0x8000000000008089ULL,0x8000000000008003ULL,
    0x8000000000008002ULL,0x8000000000000080ULL,0x000000000000800aULL,0x800000008000000aULL,
    0x8000000080008081ULL,0x8000000000008080ULL,0x0000000080000001ULL,0x8000000080008008ULL
    };

    static constexpr uint64_t ROL(const uint64_t x, const uint8_t n) noexcept {
    return (x << n) | (x >> (64 - n));
    }

    public:
    static std::string hash(const std::string_view input) {
    constexpr size_t r = 136;
    uint64_t st[5][5]{};

    std::string msg(input);
    msg.push_back(0x01);
    while((msg.size() % r) != r - 1) msg.push_back(0x00);
    msg.push_back(0x80);

    for(size_t o = 0; o < msg.size(); o += r) {
    for(int i=0;i<17;i++){
    uint64_t v=0;
    for(int b=0;b<8;b++) v|= static_cast<uint64_t>(static_cast<uint8_t>(msg[o + i * 8 + b])) <<(8*b);
    st[i%5][i/5]^=v;
    }

    for(int rnd=0;rnd<24;rnd++){
    uint64_t B[5][5]{}, C[5]{}, D[5]{};

    for(int x=0;x<5;x++)
    C[x]=st[x][0]^st[x][1]^st[x][2]^st[x][3]^st[x][4];

    for(int x=0;x<5;x++)
    D[x]=C[(x+4)%5]^ROL(C[(x+1)%5],1);

    for(int x=0;x<5;x++)
    for(int y=0;y<5;y++)
    st[x][y]^=D[x];

    constexpr uint8_t ROTC[5][5]={
    { 0,36, 3,41,18},{ 1,44,10,45, 2},{62, 6,43,15,61},
    {28,55,25,21,56},{27,20,39, 8,14}
    };

    for(int x=0;x<5;x++)
    for(int y=0;y<5;y++)
    B[y][(2*x+3*y)%5]=ROL(st[x][y],ROTC[x][y]);

    for(int x=0;x<5;x++)
    for(int y=0;y<5;y++)
    st[x][y]=B[x][y]^((~B[(x+1)%5][y])&B[(x+2)%5][y]);

    st[0][0]^=RC[rnd];
    }
    }

    std::ostringstream out;
    for(int i=0;i<4;i++){
    uint64_t v=st[i%5][i/5];
    for(int b=0;b<8;b++)
    out << std::hex << std::setfill('0') << std::setw(2) << ((v >> (8*b)) & 0xff);
    }
    return out.str();
    }
    };

    /* ========================= EIP-55 Checksum ========================= */

    export template<typename T>
    concept StringLike = requires(T a) { { std::string(a) } -> std::convertible_to<std::string>; };

    export template<StringLike S>
    std::string toChecksum(S address) {
    std::string addr(address);

    if(addr.rfind("0x",0)==0) addr=addr.substr(2);
    std::string lower;
    lower.reserve(addr.size());
    for (const char c : addr)
    lower += safeToLower(c);

    const std::string hash=Keccak256::hash(lower);
    std::string out;
    out.reserve(addr.size());

    for(size_t i=0;i<lower.size();i++){
    if(std::isalpha(lower[i]) && hexCharToInt(hash[i]) >= 8)
    out += safeToUpper(lower[i]);
    else
    out += lower[i];
    }
    return "0x"+out;
    }