content: package dk.alexandra.fresco.lib.common.math.integer.exp;
  
  import dk.alexandra.fresco.framework.DRes;
  import dk.alexandra.fresco.framework.builder.Computation;
  import dk.alexandra.fresco.framework.builder.numeric.Numeric;
  import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric;
  import dk.alexandra.fresco.framework.value.SInt;
  import dk.alexandra.fresco.lib.common.math.AdvancedNumeric;
  import java.math.BigInteger;
  
  /**
   * Computes the exponentiation of a number. We require the knowledge of the maximum bit size of the
   * exponent.
   */
  public class Exponentiation implements Computation<SInt, ProtocolBuilderNumeric> {
  
    private final DRes<SInt> input;
    private final DRes<SInt> exponent;
    private final int maxExponentBitLength;
  
    public Exponentiation(DRes<SInt> input, DRes<SInt> exponent,
        int maxExponentBitLength) {
      this.input = input;
      this.exponent = exponent;
      this.maxExponentBitLength = maxExponentBitLength;
    }
  
    @Override
    public DRes<SInt> buildComputation(ProtocolBuilderNumeric builder) {
      return builder.seq((seq) ->
          AdvancedNumeric.using(seq).toBits(exponent, maxExponentBitLength)
      ).seq((seq, bits) -> {
        DRes<SInt> e = input;
        DRes<SInt> result = null;
        Numeric numeric = seq.numeric();
        for (DRes<SInt> bit : bits) {
          /*
           * result += bits[i] * (result * r - r) + r
           *
           *  aka.
           *
           *            result       if bits[i] = 0
           * result = {
           *            result * e   if bits[i] = 1
           */
          if (result == null) {
            DRes<SInt> sub = numeric.sub(e, BigInteger.ONE);
            result = numeric.add(BigInteger.ONE, numeric.mult(bit, sub));
          } else {
            DRes<SInt> sub = numeric.sub(numeric.mult(result, e), result);
            result = numeric.add(result, numeric.mult(bit, sub));
          }
          e = numeric.mult(e, e);
        }
        return result;
      });
    }
  }
  