Created
March 11, 2024 16:31
-
-
Save ARR4N/f6f7b9f29477f0759e85aba12974c360 to your computer and use it in GitHub Desktop.
Solution builder for https://www.curta.wtf/golf/2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The factorial binary builds solutions for the 2nd Curta gas-golfing course. | |
package main | |
import ( | |
"fmt" | |
"math/bits" | |
"github.com/ethereum/go-ethereum/common" | |
. "github.com/solidifylabs/specops" //lint:ignore ST1001 SpecOps DSL is designed to be dot-imported | |
"github.com/solidifylabs/specops/specopscli" | |
"github.com/solidifylabs/specops/stack" | |
"github.com/solidifylabs/specops/types" | |
) | |
func code() Code { | |
// ---------------------------------------- | |
// ========== START EDITING HERE ========== | |
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv | |
// Cloned from https://github.com/solidifylabs/specops/tree/main/getting-started | |
const ( | |
_ = Inverted(DUP1) + iota // Result | |
Input | |
) | |
factorial := Code{ | |
PUSH(1), // Result | |
// The selector is irrelevant so just load the input word. | |
Fn(CALLDATALOAD, PUSH(4)), | |
Fn(JUMPI, | |
PUSH("revert"), | |
Fn(GT, Input, PUSH(57)), | |
), | |
stack.ExpectDepth(2), | |
Fn(JUMP, | |
Fn(SUB, | |
PUSH("return"), | |
Fn(SHL, PUSH(2) /* top of stack = Input */), | |
), | |
), | |
stack.ExpectDepth(1), | |
} | |
for i := 0; i < 56; i++ { // note NOT 57 | |
var mul types.Bytecoder | |
switch m := uint64(57 - i); { | |
case m&(m-1) == 0: | |
mul = Fn(SHL, PUSH(bits.Len64(m)-1)) | |
default: | |
mul = Fn(MUL, PUSH(m)) | |
} | |
factorial = append( | |
factorial, | |
// The actual JUMPDEST label is irrelevant, but the compiler insists | |
// that they must be distinct. | |
JUMPDEST(fmt.Sprintf("%d", i)), stack.SetDepth(1), | |
mul, | |
) | |
} | |
// If we'd bounded the loop above by 57 instead of 56 then we'd have a no-op | |
// multiplication by 1 here, for 8 gas (PUSH + MUL). Removing it entirely | |
// would require adjusting the earlier JUMP, negating any benefits, so we | |
// can instead replace it with 3 extra JUMPDESTs for 3 gas. | |
for i := 0; i < 4; i++ { | |
factorial = append(factorial, | |
JUMPDEST(fmt.Sprintf("a%d", i)), stack.SetDepth(1), | |
) | |
} | |
return append( | |
factorial, | |
JUMPDEST("return"), stack.SetDepth(1), | |
Fn(MSTORE, PUSH0), | |
Fn(RETURN, PUSH0, PUSH(32)), | |
JUMPDEST("revert"), stack.SetDepth(0), | |
Fn(REVERT, PUSH0, PUSH0), | |
) | |
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
// ========== STOP EDITING HERE =========== | |
// ---------------------------------------- | |
} | |
func main() { | |
specopscli.Run(code()) | |
} | |
// Stop unused imports being removed. | |
var ( | |
_ = stack.ExpectDepth(0) | |
_ = common.Address{} | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"testing" | |
"github.com/holiman/uint256" | |
) | |
func TestFactorial(t *testing.T) { | |
want := uint256.NewInt(1) | |
c := code() | |
for i := uint64(0); i < 18; i++ { | |
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { | |
bigI := uint256.NewInt(i) | |
in := bigI.Bytes32() | |
if i != 0 { | |
want.Mul(want, bigI) | |
} | |
gotBuf, err := c.Run(append([]byte{0xd0, 0x97, 0xbc, 0x0d}, in[:]...)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
got := new(uint256.Int).SetBytes(gotBuf) | |
if !got.Eq(want) { | |
t.Errorf("%d! got %d; want %d", i, got, want) | |
} | |
}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module github.com/solidifylabs/specops | |
go 1.20 | |
require ( | |
github.com/ethereum/go-ethereum v1.13.14 | |
github.com/gdamore/tcell/v2 v2.7.1 | |
github.com/google/go-cmp v0.5.9 | |
github.com/holiman/uint256 v1.2.4 | |
github.com/rivo/tview v0.0.0-20240225120200-5605142ca62e | |
github.com/spf13/cobra v1.5.0 | |
golang.org/x/sync v0.5.0 | |
) | |
require ( | |
github.com/bits-and-blooms/bitset v1.10.0 // indirect | |
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect | |
github.com/consensys/bavard v0.1.13 // indirect | |
github.com/consensys/gnark-crypto v0.12.1 // indirect | |
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect | |
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect | |
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect | |
github.com/gdamore/encoding v1.0.0 // indirect | |
github.com/inconshreveable/mousetrap v1.0.0 // indirect | |
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | |
github.com/mattn/go-runewidth v0.0.15 // indirect | |
github.com/mmcloughlin/addchain v0.4.0 // indirect | |
github.com/rivo/uniseg v0.4.7 // indirect | |
github.com/spf13/pflag v1.0.5 // indirect | |
github.com/supranational/blst v0.3.11 // indirect | |
golang.org/x/crypto v0.17.0 // indirect | |
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect | |
golang.org/x/sys v0.17.0 // indirect | |
golang.org/x/term v0.17.0 // indirect | |
golang.org/x/text v0.14.0 // indirect | |
rsc.io/tmplfunc v0.0.3 // indirect | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment