(`!p. prime(p) ==> (
GEN_TAC THEN DISCH_TAC THEN
ASM_CASES_TAC `p = 0` THENL [ASM_MESON_TAC[
PRIME_0]; ALL_TAC] THEN
ASM_CASES_TAC `p = 1` THENL [ASM_MESON_TAC[
PRIME_1]; ALL_TAC] THEN
ASM_CASES_TAC `p = 2` THENL
[ASM_REWRITE_TAC[] THEN CONV_TAC NUM_REDUCE_CONV THEN
REWRITE_TAC[
CONG_REFL];
ALL_TAC] THEN
SUBGOAL_THEN `
FACT(p - 1) =
FACT(p - 2) * (p - 1)` SUBST1_TAC THENL
[SUBGOAL_THEN `p - 1 = SUC(p - 2)`
(fun th -> REWRITE_TAC[th;
FACT;
MULT_AC]) THEN
ASM_ARITH_TAC;
ALL_TAC] THEN
GEN_REWRITE_TAC LAND_CONV [ARITH_RULE `x = 1 * x`] THEN
MATCH_MP_TAC
CONG_MULT THEN REWRITE_TAC[
CONG_REFL] THEN
REWRITE_TAC[
FACT_PRODUCT_ALT] THEN MATCH_MP_TAC
PRODUCT_PAIRUP THEN
REWRITE_TAC[
FINITE_NUMSEG;
IN_NUMSEG] THEN
X_GEN_TAC `x:num` THEN STRIP_TAC THEN
MP_TAC(SPECL [`p:num`; `x:num`]
CONG_UNIQUE_INVERSE_PRIME) THEN
ASM_REWRITE_TAC[] THEN ANTS_TAC THENL
[ASM_ARITH_TAC; ALL_TAC] THEN
REWRITE_TAC[
EXISTS_UNIQUE_THM] THEN MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
[MATCH_MP_TAC
MONO_EXISTS;
REPEAT(MATCH_MP_TAC
MONO_FORALL THEN GEN_TAC) THEN
DISCH_TAC THEN STRIP_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
ASM_REWRITE_TAC[] THEN ASM_ARITH_TAC] THEN
X_GEN_TAC `y:num` THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THENL
[ASM_CASES_TAC `y = 1` THEN
ASM_REWRITE_TAC[ARITH_RULE `2 <= y <=> 0 < y /\ ~(y = 1)`] THEN
UNDISCH_TAC `(x * y == 1) (mod p)` THEN ASM_REWRITE_TAC[
MULT_CLAUSES] THEN
ASM_SIMP_TAC[
CONG;
MOD_LT; ARITH_RULE `x <= p - 2 /\ ~(p = 0) ==> x < p`;
ARITH_RULE `~(p = 0) /\ ~(p = 1) ==> 1 < p`] THEN
UNDISCH_TAC `2 <= x` THEN ARITH_TAC;
MATCH_MP_TAC(ARITH_RULE `y < p /\ ~(y = p - 1) ==> y <= p - 2`) THEN
ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
UNDISCH_TAC `(x * y == 1) (mod p)` THEN ASM_REWRITE_TAC[] THEN
DISCH_TAC THEN SUBGOAL_THEN `(x + 1 == 0) (mod p)` MP_TAC THENL
[ALL_TAC;
REWRITE_TAC[
CONG_0] THEN DISCH_THEN(MP_TAC o MATCH_MP
DIVIDES_LE) THEN
MAP_EVERY UNDISCH_TAC [`2 <= x`; `x <= p - 2`] THEN ARITH_TAC] THEN
MATCH_MP_TAC
CONG_TRANS THEN EXISTS_TAC `x * p:num` THEN CONJ_TAC THENL
[ALL_TAC; REWRITE_TAC[
CONG_0] THEN MESON_TAC[divides;
MULT_SYM]] THEN
SUBGOAL_THEN `x * p = x + x * (p - 1)` SUBST1_TAC THENL
[REWRITE_TAC[
LEFT_SUB_DISTRIB;
MULT_CLAUSES] THEN
ONCE_REWRITE_TAC[
ADD_SYM] THEN MATCH_MP_TAC(GSYM
SUB_ADD) THEN
GEN_REWRITE_TAC LAND_CONV [ARITH_RULE `x = x * 1`] THEN
ASM_REWRITE_TAC[
LE_MULT_LCANCEL] THEN
UNDISCH_TAC `~(p = 0)` THEN ARITH_TAC;
ALL_TAC] THEN
ONCE_REWRITE_TAC[
CONG_SYM] THEN MATCH_MP_TAC
CONG_ADD THEN
ASM_REWRITE_TAC[
CONG_REFL];
FIRST_X_ASSUM SUBST_ALL_TAC THEN
SUBGOAL_THEN `((x + 1) * (x - 1) == 0) (mod p)` MP_TAC THENL
[ALL_TAC;
REWRITE_TAC[
CONG_0] THEN
DISCH_THEN(MP_TAC o CONJ (ASSUME `prime p`)) THEN
DISCH_THEN(MP_TAC o MATCH_MP
PRIME_DIVPROD) THEN
DISCH_THEN(DISJ_CASES_THEN (MP_TAC o MATCH_MP
DIVIDES_LE)) THEN
MAP_EVERY UNDISCH_TAC
[`2 <= x`; `x <= p - 2`; `~(p = 1)`; `~(p = 0)`] THEN
ARITH_TAC] THEN
ONCE_REWRITE_TAC[GSYM(SPEC `1`
CONG_ADD_LCANCEL_EQ)] THEN
SUBGOAL_THEN `1 + (x + 1) * (x - 1) = x * x`
(fun th -> ASM_REWRITE_TAC[th; ARITH]) THEN
REWRITE_TAC[
LEFT_SUB_DISTRIB] THEN
MATCH_MP_TAC(ARITH_RULE
`(x + 1) * 1 <= (x + 1) * x
==> 1 + (x + 1) * x - (x + 1) * 1 = x * x`) THEN
REWRITE_TAC[
LE_MULT_LCANCEL] THEN UNDISCH_TAC `2 <= x` THEN ARITH_TAC]);;