Definition times2(x: int): int := 
  Int.and
    (Int.xor (Int.shl x (Int.repr 1))
             (if Int.eq (Int.and x (Int.repr 128)) Int.zero then Int.zero else Int.repr 27))
    (Int.repr 255).Definition pow2(e: Z): int := repeat_op e (Int.repr 1) times2.Definition times3(x: int): int := 
  Int.and
    (Int.xor x (Int.xor (Int.shl x (Int.repr 1))
                        (if Int.eq (Int.and x (Int.repr 128)) Int.zero then Int.zero else Int.repr 27)))
    (Int.repr 255).Definition pow3(e: Z): int := repeat_op e (Int.repr 1) times3.Fixpoint log3_nat(p: int)(n: nat): Z :=
  if Int.eq p (pow3 (Z.of_nat n)) then Z.of_nat n
  else match n with
  | O => -1 (* illegal argument *)
  | S m => log3_nat p m
  end.(* Note: For (log3 1), we have two possible return values: 0 and 255.
   We choose 255, because then both the domain and the codomain of log3 are 1..255. *)
Definition log3(p: int): Z := log3_nat p 255.Definition mul(x y: int): int :=
  if Int.eq x Int.zero then Int.zero else
  if Int.eq y Int.zero then Int.zero else
  pow3 (Int.unsigned (Int.mods (Int.repr (log3 x + log3 y)) (Int.repr 255))).

Lemma invert_pow3: forall i, 1 <= i < 256 -> exists j, 1 <= j < 256 /\ i = (Int.unsigned (pow3 j)).