(** Explicit formulas for carry bits during addition. Conceptually, the theory
 * here matches the bitblasting rules for integers. However, the vector of
 * carry bits is represented as a [Z] so it can be used in bitwise operations.
 * The last three lemmas about [addcarries] are the main interface, but the
 * generalization [adccarries] is provided as the same theory applies. *)

Definition adccarries (x y : Z) (c : bool) := (x + y + Z.b2z c) .^ (x .^ y).Definition addcarries (x y : Z)            := (x + y)           .^ (x .^ y).

(* Specifications: *)
Lemma addcarries_ok x y : addcarries x y = adccarries x y false.
Lemma addcarryeqn (x y : Z) (c0 : bool) (z := (x + y + Z.b2z c0)) (c := z .^ (x .^ y)) : Z.shiftr c 1 = (x .& y) .| (c .& (x .^ y)).
Lemma testbit_adccarries_0 x y c : Z.testbit (adccarries x y c) 0 = c.
Lemma shiftr_adccarries_1 x y c : Z.shiftr (adccarries x y c) 1 = (x .& y) .| ((x .^ y) .& (adccarries x y c)).
Lemma testbit_adccarries_pos x y c i (Hi : 0 < i) : Z.testbit (adccarries x y c) i = (x.[i-1] && y.[i-1] || (x.[i-1]^^y.[i-1]) && (adccarries x y c).[i-1])%bool.
Lemma testbit_addcarries_0 x y : Z.testbit (addcarries x y) 0 = false.
Lemma shiftr_addcarries_1 x y : Z.shiftr (addcarries x y) 1 = (x .& y) .| ((x .^ y) .& (addcarries x y)).
Lemma testbit_addcarries_pos x y i (Hi : 0 < i) : Z.testbit (addcarries x y) i = (x.[i-1] && y.[i-1] || (x.[i-1]^^y.[i-1]) && (addcarries x y).[i-1])%bool.
Lemma addcarries_lor_land x y : addcarries (x .| y) (x .& y) = addcarries x y.
Lemma sub_lor_land x y : (x .| y) - (x .& y) = (x .^ y).
Lemma add_lor_land x y : (x .| y) + (x .& y) = (x + y).
Lemma sub_lor_l_same_l x y : y .| x - y = x .& .~ y.
Lemma sub_lor_l_same_r x y : x .| y - y = x .& .~ y.
Lemma sub_landn_rlandn x y : x.&.~y - .~x .& y = x - y.
Lemma sub_land_same_l x y : x - x.&y = x .& .~y.
Lemma add_lxor_2land x y : (x .^ y) + 2*(x .& y) = x + y.
Lemma sub_2lor_lxor x y : 2*(x .| y) - x .^ y = x + y.
Lemma sub_lxor_2rlandn x y : x .^ y - 2*(.~x .& y) = x - y.
Lemma sub_2landn_lxor x y : 2*(x.&.~y) - x.^y = x - y.