func main() {
	{
		// testing that crypto works back and forth
		t := []byte("some secret stuff AAAA")
		ct := make([]byte, len(t))
		MTEncrypt(0, ct, t)
		t2 := make([]byte, len(t))
		MTEncrypt(0, t2, ct)
		fmt.Println(bytes.Equal(t, t2))
	}
	{
		// generate random bytes with AAA's appended
		t := util.RandBytes(int(util.RandByte()))
		knownText := "AAAAAAAAAAAAA"
		t = append(t, []byte(knownText)...)
		ct := make([]byte, len(t))
		MTEncrypt(int(util.RandByte())*int(util.RandByte()), ct, t)
		for i := 0; i < 0xFFFF; i++ {
			z := make([]byte, len(ct))
			MTEncrypt(i, z, ct)
			if string(z[len(z)-len(knownText):]) == knownText {
				fmt.Println("Found the key:", i)
				break
			}
		}
	}
	{
		// generate "random" "password reset token"
		mt := util.NewMT19337(uint64(time.Now().Unix()))
		token := mt.Next()
		time.Sleep(1 * time.Second)
		fmt.Println("Is MT19337 token: ", isMT19337Token(token))
	}
}
func encryptOracle(src []byte) []byte {
	key := util.RandAes128()
	block, _ := aes.NewCipher(key)
	out := make([]byte, len(src))
	copy(out, src)

	// random prepend and append
	prefixSize := util.RandByte()%10 + 5
	postfixSize := util.RandByte()%10 + 5
	postfix := util.RandBytes(int(postfixSize))
	out = append(util.RandBytes(int(prefixSize)), out...)
	out = append(out, postfix...)
	// padding
	out = util.PadTo(out, 16)
	// fmt.Println("before enc", out)

	// random encryption mode
	mode := util.RandByte()
	if mode%2 == 0 {
		// ecb
		fmt.Println("ecb")
		util.ECBEncrypt(block, out, out)
	} else {
		// cbc
		fmt.Println("cbc")
		iv := util.RandAes128()
		util.CBCEncrypt(block, iv, out, out)
	}
	return out
}
func getMsg() (ct, iv []byte) {
	ct, err := base64.StdEncoding.DecodeString(msgs[util.RandByte()%10])
	if err != nil {
		log.Fatal("Cannot decode", err)
	}
	iv = util.RandAes128()
	block, _ := aes.NewCipher(key)
	ct = util.PadTo(ct, block.BlockSize())
	util.CBCEncrypt(block, iv, ct, ct)
	return ct, iv
}
Think "STIMULUS" and "RESPONSE".
*/

import (
	"bytes"
	"crypto/aes"
	"cryptopals/util"
	"fmt"
)

type oracleFunc func(src []byte) []byte

var (
	key       = util.RandAes128()
	prefixLen = int(util.RandByte())%32 + 1
	prefix    = util.RandBytes(prefixLen)
)

func encryptOracle(src []byte) []byte {
	block, _ := aes.NewCipher(key)
	out := make([]byte, len(src))
	copy(out, src)

	target := []byte("secret bytes. nobody is gonna read them.")
	out = append(prefix, out...)
	out = append(out, target...)
	out = util.PadTo(out, 16)
	// fmt.Println("before enc", out)
	util.ECBEncrypt(block, out, out)