Rever

This was just me getting used to hackmd. Cant find delete button lol

You send runtime bytecode to setup.challenge().deploy()

will be grabbed from rever.etk using vm.ffi and ./script/compile.sh

Example inputs

find string through cast --format-bytes32-string <string>
or https://www.rapidtables.com/convert/number/ascii-to-hex.html

"paradigm"
70 61 72 61 64 69 67 6d 00000000000000
p a r a d i g m 0000000000

"tattarrattat"
0x7461747461727261747461740000000000000000000000000000000000000000

Useful opcodes

calldataload
loads 32bytes of calldata following your stack input [offset]

calldatasize
size of string

msize (before allocating)
0

chainid (on mainnet)
1

selfbalance
ANY just need to transfer in amount

byte
can isolate bytes to check equality
inputs [i, word]
i as 0 is most sig byte (left), i as 31 is least sig byte (right)

Solving

runtimeBytecode:
    # your runtime bytecode
    # we need this to be less than 51 bytes so that we can palindrome it

    # initialize word - this stack item needs to be here for the entire puzzle
    msize # this is 0 at the moment
    calldataload # this is the string NOT abi encoded
    
    # word_start is always 0
    msize

    # initialize word_end (calldatasize - 1)
    chainid
    calldatasize # this is length of string - only needed to set up word_end
    sub

    # initialize loop counter
    msize

    # exit conditions are either byte eq fails (false) or word_start >= word_end (true)
    # enter loop with [loopCount, word_end, word_start, word]
    loop:
        jumpdest # [loopCount, word_end, word_start, word]
        # dec cur_end
        dup1
        dup3 # [word_end, loopCount, loopCount, word_end, word_start, word]
        sub # [cur_end, loopCount, word_end, word_start, word]

        # inc cur_start
        dup4
        dup3
        add # [cur_start, cur_end, loopCount, word_end, word_start, word]
        
        # check if palindrome is finished
        dup2
        dup2 # [cur_start, cur_end, cur_start, cur_end, loopCount, word_end, word_start, word]
        lt # [start<end, cur_start, cur_end, loopCount, word_end, word_start, word]
        iszero # [start>=end, cur_start, cur_end, loopCount, word_end, word_start, word]
        push1 win
        jumpi
        # [cur_start, cur_end, loopCount, word_end, word_start, word]
        
        # get word_start byte
        dup6 # [word, cur_start, cur_end, loopCount, word_end, word_start, word]
        swap1 # [cur_start, word, cur_end, loopCount, word_end, word_start, word]
        byte # [start_byte, cur_end, loopCount, word_end, word_start, word]

        # get word_end byte
        swap1 # [cur_end, start_byte, loopCount, word_end, word_start, word]
        dup6 # [word, cur_end, start_byte, loopCount, word_end, word_start, word]
        swap1 # [cur_end, word, start_byte, loopCount, word_end, word_start, word]
        byte # [end_byte, start_byte, loopCount, word_end, word_start, word]

        # check if bytes are not equal
        eq # [equal, loopCount, word_end, word_start, word]
        iszero # [!equal, loopCount, word_end, word_start, word]
        push1 lose
        jumpi # jump if lost

        # otherwise: increment loop counter, rearrange stack and continue
        # [loopCount, word_end, word_start, word]
        chainid
        add # [loopCount+1, word_end, word_start, word]

        push1 loop
        jump
    
    lose:
        jumpdest
        chainid
        selfbalance
        return # return false, no palindrome

    win:
        jumpdest
        chainid
        selfbalance
        mstore8
        chainid
        selfbalance
        return # return true, palindrome
# 593559463603595b80820383820181811015602a5785901a9085901a141560265746016007565b4647f35b4647534647f3
# 49 bytes, just under the limit
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../src/rever/public/contracts/Setup.sol";

contract ATest is Test {
    Setup setup;
    bytes etkCode;

    function setUp() public {
        setup = new Setup();
        string[] memory inputs = new string[](2);
        /**
         * windows: scripts/compile.bat
         * linux  : scripts/compile.sh
         */
        inputs[0] = "./script/compile.sh";

        // path/to/contract.etk
        // Need to palindrome this before solving fr, tho fwd works
        inputs[1] = "./src/rever/public/contracts/rever.etk";

        etkCode = vm.ffi(inputs);
    }

    function testRever() public {
        Challenge challenge = setup.challenge();
        challenge.deploy(etkCode); 
        console2.logBytes(challenge.fwd().code);
        console2.logBytes(challenge.rev().code);
        
        setup.test("1aba1");
        setup.test("2a2");
        setup.test("3abababa3");
        setup.test("a");
        setup.test("paradigm");
    }
}