-- WadrayVerification/Aux.lean

import CorelibVerification.Aux.ZMod

import Aegis.Aux.Bool

import Aegis.Aux.ZMod.DivMod

open Sierra

def Wad : Type := UInt128

namespace Wad

def WAD_SCALE : ℕ := 1000000000000000000

variable (w w' : Wad)

protected def toZMod : UInt128 := w

protected def toRat : ℚ := w.toZMod.val / WAD_SCALE

-- Repository definitions used:
content: protected def Wad.mul : Wad := (w.toZMod.val * w'.toZMod.val / WAD_SCALE : UInt128)

content: instance : Mul Wad := ⟨Wad.mul⟩

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: def Wad : Type := UInt128

content: def WAD_SCALE : ℕ := 1000000000000000000

content: protected def toZMod : UInt128 := w

content: protected def toRat : ℚ := w.toZMod.val / WAD_SCALE

-- Local lemmas used:
content: theorem Rat.nat_cast_div_eq {a b : ℕ} :
    ↑(a / b) = (a : ℚ) / (b : ℚ) - ↑(a % b) / (b : ℚ)

content: theorem WAD_SCALE_pos : 0 < WAD_SCALE

content: theorem WAD_SCALE_rat_pos : 0 < (WAD_SCALE : ℚ)

content: protected theorem mul_def :
    w * w' = (w.toZMod.val * w'.toZMod.val / WAD_SCALE  : UInt128)

-- Target theorem and proof:
theorem toRat_mul (h : w.toZMod.val * w'.toZMod.val / WAD_SCALE < U128_MOD) :
    |(w * w').toRat - w.toRat * w'.toRat| < 1 / WAD_SCALE
:= by
  simp only [Wad.toRat, Wad.toZMod, Wad.mul_def, Int.natCast_natAbs] at *
  simp only [ZMod.val_natCast, ZMod.natCast_val] at *
  rw [Nat.mod_eq_of_lt h, div_mul_div_comm, ← div_div, ← sub_div, abs_div,
    Nat.abs_cast, div_lt_div_right WAD_SCALE_rat_pos, Rat.nat_cast_div_eq]
  simp only [Nat.cast_mul, ZMod.natCast_val, sub_sub_cancel_left, abs_neg]
  rw [abs_div, Nat.abs_cast, Nat.abs_cast, div_lt_one WAD_SCALE_rat_pos,
    Nat.cast_lt]
  apply Nat.mod_lt _ WAD_SCALE_pos