content: package xjsnark.aes;
  
  /*Generated by MPS */
  
  import backend.structure.CircuitGenerator;
  import backend.eval.SampleRun;
  import java.math.BigInteger;
  import java.util.Arrays;
  import backend.auxTypes.UnsignedInteger;
  import backend.auxTypes.SmartMemory;
  import util.Util;
  import backend.auxTypes.Bit;
  import backend.auxTypes.ConditionalScopeTracker;
  import backend.eval.CircuitEvaluator;
  
  public class AES128 extends CircuitGenerator {
  
  
  
    public static void main(String[] args) {
      // This is the java main method. Its purpose is to make the Progam runnable in the environment 
      // This method can be left empty, or used to set Configuration params (see other examples) 
      new AES128();
    }
  
    public AES128() {
      super("AES128");
      __generateCircuit();
      this.__evaluateSampleRun(new SampleRun("Sample_Run1", true) {
        public void pre() {
  
          // assigning values to inputs 
          BigInteger keyV = new BigInteger("2b7e151628aed2a6abf7158809cf4f3c", 16);
          BigInteger msgV = new BigInteger("6bc1bee22e409f96e93d7e117393172a", 16);
          byte[] keyArray = keyV.toByteArray();
          byte[] msgArray = msgV.toByteArray();
          msgArray = Arrays.copyOfRange(msgArray, msgArray.length - 16, msgArray.length);
          keyArray = Arrays.copyOfRange(keyArray, keyArray.length - 16, keyArray.length);
          for (int i = 0; i < plaintext.length; i++) {
            plaintext[i].mapValue(BigInteger.valueOf((msgArray[i] & 0xff)), CircuitGenerator.__getActiveCircuitGenerator().__getCircuitEvaluator());
          }
          for (int i = 0; i < key.length; i++) {
            key[i].mapValue(BigInteger.valueOf((keyArray[i] & 0xff)), CircuitGenerator.__getActiveCircuitGenerator().__getCircuitEvaluator());
          }
        }
        public void post() {
          System.out.println("Circuit Output: ");
          for (int i = 0; i < key.length; i++) {
            System.out.print(ciphertext[i].getValueFromEvaluator(CircuitGenerator.__getActiveCircuitGenerator().__getCircuitEvaluator()).toString(16) + " ,");
          }
          System.out.println();
          System.out.println("Expected Output: 0x3ad77bb40d7a3660a89ecaf32466ef97");
  
          // expected ciphertext: "3ad77bb40d7a3660a89ecaf32466ef97" 
        }
  
      });
  
    }
  
  
  
    public void __init() {
      plaintext = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{16}, 8);
      ciphertext = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{16}, 8);
      key = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{16}, 8);
    }
  
    private UnsignedInteger[] plaintext;
    private UnsignedInteger[] ciphertext;
    private UnsignedInteger[] key;
    private UnsignedInteger[] expandedKey;
    private SmartMemory<UnsignedInteger> sBoxMem;
  
    public static final int[] SBOX = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
    public static final int[] RCON = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
    private static int nb = 4;
    private static int nk = 4;
    @Override
    public void __defineInputs() {
      super.__defineInputs();
  
  
  
      plaintext = (UnsignedInteger[]) UnsignedInteger.createInputArray(CircuitGenerator.__getActiveCircuitGenerator(), Util.getArrayDimensions(plaintext), 8);
      key = (UnsignedInteger[]) UnsignedInteger.createInputArray(CircuitGenerator.__getActiveCircuitGenerator(), Util.getArrayDimensions(key), 8);
  
  
  
  
  
  
  
  
  
  
  
  
    }
    @Override
    public void __defineOutputs() {
      super.__defineOutputs();
      UnsignedInteger.makeOutput(this, ciphertext);
  
  
  
  
  
  
  
  
  
    }
    @Override
    public void __defineVerifiedWitnesses() {
      super.__defineVerifiedWitnesses();
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
    }
    @Override
    public void __defineWitnesses() {
      super.__defineWitnesses();
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
    }
    public void outsource() {
  
      // convert the SBOX to xjsnark type (to make the typesystem happy later) 
      UnsignedInteger[] sBox = UnsignedInteger.instantiateFrom(8, SBOX);
  
      // load the random access memory for the SBox.  
      sBoxMem = new SmartMemory(sBox, UnsignedInteger.__getClassRef(), new Object[]{"8"});
  
      //  expand the AES key 
      expandedKey = expandKey();
  
      UnsignedInteger[][] state = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4, 4}, 8);
      int idx = 0;
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 4; k++) {
          state[k][j].assign(plaintext[idx++], 8);
        }
      }
      state = addRoundkey(state, 0, 3);
      int nr = 6 + nk;
      for (int round = 1; round < nr; round++) {
        state = subState(state);
        state = shiftRows(state);
        state = mixColumns(state);
        state = addRoundkey(state, round * 4 * 4, (round + 1) * 4 * 4 - 1);
  
        // note: the methods substate(), shiftRows(), mixColumns(), addRoundKey() could be also be  
        // written in a way that updates the state array directly in place. 
  
      }
      state = subState(state);
      state = shiftRows(state);
      state = addRoundkey(state, nr * nb * 4, (nr + 1) * nb * 4);
  
      idx = 0;
      for (int j = 0; j < 4; j++) {
        for (int k = 0; k < 4; k++) {
          ciphertext[idx].assign(state[k][j], 8);
          idx++;
        }
      }
    }
    private UnsignedInteger[] expandKey() {
  
      int nr = nk + 6;
      UnsignedInteger[] expandedKey = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{nb * (nr + 1) * 4}, 8);
      UnsignedInteger[][] w = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{nb * (nr + 1), 4}, 8);
      UnsignedInteger[] tmp;
  
      // using native java types for loops with bounds known at compilation time 
      int i = 0;
  
      while (i < nk) {
        w[i] = new UnsignedInteger[]{key[4 * i].copy(8), key[4 * i + 1].copy(8), key[4 * i + 2].copy(8), key[4 * i + 3].copy(8)};
        i++;
      }
      while (i < nb * (nr + 1)) {
        tmp = w[i - 1];
        if (i % nk == 0) {
          tmp = rotWord(tmp);
          tmp = subWord(tmp);
          tmp[0].assign(tmp[0].xorBitwise(UnsignedInteger.instantiateFrom(8, RCON[i / 4])), 8);
        }
        for (int v = 0; v < 4; v++) {
          w[i][v].assign(w[i - nk][v].xorBitwise(tmp[v]), 8);
        }
        i++;
      }
  
      int idx = 0;
      for (int k = 0; k < nb * (nr + 1); k++) {
        for (int j = 0; j < 4; j++) {
          expandedKey[idx].assign(w[k][j], 8);
          idx++;
        }
      }
      return expandedKey;
    }
    private UnsignedInteger[] rotWord(UnsignedInteger[] w) {
      UnsignedInteger[] newW = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{w.length}, 8);
      for (int j = 0; j < w.length; j++) {
        newW[j].assign(w[(j + 1) % w.length], 8);
      }
      return newW;
    }
    private UnsignedInteger[] subWord(UnsignedInteger[] w) {
      UnsignedInteger[] newW = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{w.length}, 8);
      for (int j = 0; j < w.length; j++) {
        newW[j].assign(sBoxMem.read(w[j]), 8);
      }
      return newW;
    }
    private UnsignedInteger[][] subState(UnsignedInteger[][] state) {
      UnsignedInteger[][] newState = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4, 4}, 8);
      for (int i = 0; i < state.length; i++) {
        for (int j = 0; j < state[i].length; j++) {
          newState[i][j].assign(sBoxMem.read(state[i][j]), 8);
        }
      }
      return newState;
    }
    private UnsignedInteger gal_mul_const(UnsignedInteger x, int c) {
  
      UnsignedInteger p = new UnsignedInteger(8, new BigInteger("0"));
      for (int counter = 0; counter < 8; counter += 1) {
        if ((c & 1) != 0) {
          p.assign(p.xorBitwise(x), 8);
        }
        c = c >> 1;
        // c is a java integer, we can use the == operator. Otherwise, the eq operator should be used 
        // we use break; here as this is also a static java loop -- support for the runtime bWhile break; will be added. 
        if (c == 0) {
          break;
        }
        Bit[] xBits = x.getBitElements();
        Bit hi = xBits[7].copy();
        x.assign(x.shiftLeft(1), 8);
        UnsignedInteger tmp = x.xorBitwise(new BigInteger("" + 0x1b)).copy(8);
  
        // this is a runtime circuit condition 
        {
          Bit bit_l0c0mb = hi.copy();
          boolean c_l0c0mb = CircuitGenerator.__getActiveCircuitGenerator().__checkConstantState(bit_l0c0mb);
          if (c_l0c0mb) {
            if (bit_l0c0mb.getConstantValue()) {
              x.assign(tmp, 8);
            } else {
  
            }
          } else {
            ConditionalScopeTracker.pushMain();
            ConditionalScopeTracker.push(bit_l0c0mb);
            x.assign(tmp, 8);
  
            ConditionalScopeTracker.pop();
  
            ConditionalScopeTracker.push(new Bit(true));
  
            ConditionalScopeTracker.pop();
            ConditionalScopeTracker.popMain();
          }
  
        }
      }
      return p;
    }
    private UnsignedInteger[][] shiftRows(UnsignedInteger[][] state) {
      UnsignedInteger[][] newState = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4, 4}, 8);
      for (int j = 0; j < 4; j++) {
        newState[0][j].assign(state[0][j], 8);
        newState[1][j].assign(state[1][(j + 1) % 4], 8);
        newState[2][j].assign(state[2][(j + 2) % 4], 8);
        newState[3][j].assign(state[3][(j + 3) % 4], 8);
      }
      return newState;
    }
    private UnsignedInteger[][] mixColumns(UnsignedInteger[][] state) {
  
      UnsignedInteger[] a = (UnsignedInteger[]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4}, 8);
      UnsignedInteger[][] newState = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4, 4}, 8);
  
      for (int c = 0; c < 4; c++) {
        for (int i = 0; i < 4; i++) {
          a[i].assign(state[i][c], 8);
        }
        newState[0][c].assign(gal_mul_const(a[0].copy(8), 2).xorBitwise(gal_mul_const(a[1].copy(8), 3)).xorBitwise(a[2]).xorBitwise(a[3]), 8);
        newState[1][c].assign(a[0].xorBitwise(gal_mul_const(a[1].copy(8), 2)).xorBitwise(gal_mul_const(a[2].copy(8), 3)).xorBitwise(a[3]), 8);
        newState[2][c].assign(a[0].xorBitwise(a[1]).xorBitwise(gal_mul_const(a[2].copy(8), 2)).xorBitwise(gal_mul_const(a[3].copy(8), 3)), 8);
        newState[3][c].assign(gal_mul_const(a[0].copy(8), 3).xorBitwise(a[1]).xorBitwise(a[2]).xorBitwise(gal_mul_const(a[3].copy(8), 2)), 8);
      }
      return newState;
    }
    private UnsignedInteger[][] addRoundkey(UnsignedInteger[][] state, int from, int to) {
      UnsignedInteger[][] newState = (UnsignedInteger[][]) UnsignedInteger.createZeroArray(CircuitGenerator.__getActiveCircuitGenerator(), new int[]{4, 4}, 8);
      int idx = 0;
      for (int j = 0; j < 4; j++) {
        for (int i = 0; i < 4; i++) {
          newState[i][j].assign(state[i][j].xorBitwise(expandedKey[from + idx]), 8);
          idx++;
        }
      }
      return newState;
    }
  
    public void __generateSampleInput(CircuitEvaluator evaluator) {
      __generateRandomInput(evaluator);
    }
  
  }
  