needs "Library/prime.ml";; needs "Library/pocklington.ml";; needs "Library/binomial.ml";; prioritize_num();; let FERMAT_PRIME_CONV n = let tm = subst [mk_small_numeral n,`x:num`] `prime(2 EXP (2 EXP x) + 1)` in (RAND_CONV NUM_REDUCE_CONV THENC PRIME_CONV) tm;; FERMAT_PRIME_CONV 0;; FERMAT_PRIME_CONV 1;; FERMAT_PRIME_CONV 2;; FERMAT_PRIME_CONV 3;; FERMAT_PRIME_CONV 4;; FERMAT_PRIME_CONV 5;; FERMAT_PRIME_CONV 6;; FERMAT_PRIME_CONV 7;; FERMAT_PRIME_CONV 8;; let CONG_TRIVIAL = prove (`!x y. n divides x /\ n divides y ==> (x == y) (mod n)`, MESON_TAC[CONG_0; CONG_SYM; CONG_TRANS]);; let LITTLE_CHECK_CONV tm = EQT_ELIM((RATOR_CONV(LAND_CONV NUM_EXP_CONV) THENC CONG_CONV) tm);; LITTLE_CHECK_CONV `(9 EXP 8 == 9) (mod 3)`;; LITTLE_CHECK_CONV `(9 EXP 3 == 9) (mod 3)`;; LITTLE_CHECK_CONV `(10 EXP 7 == 10) (mod 7)`;; LITTLE_CHECK_CONV `(2 EXP 7 == 2) (mod 7)`;; LITTLE_CHECK_CONV `(777 EXP 13 == 777) (mod 13)`;; let DIVIDES_FACT_PRIME = prove (`!p. prime p ==> !n. p divides (FACT n) <=> p <= n`, GEN_TAC THEN DISCH_TAC THEN INDUCT_TAC THEN REWRITE_TAC[FACT; LE] THENL [ASM_MESON_TAC[DIVIDES_ONE; PRIME_0; PRIME_1]; ASM_MESON_TAC[PRIME_DIVPROD_EQ; DIVIDES_LE; NOT_SUC; DIVIDES_REFL; ARITH_RULE `~(p <= n) /\ p <= SUC n ==> p = SUC n`]]);; let DIVIDES_BINOM_PRIME = prove (`!n p. prime p /\ 0 < n /\ n < p ==> p divides binom(p,n)`, REPEAT STRIP_TAC THEN MP_TAC(AP_TERM `(divides) p` (SPECL [`p - n`; `n:num`] BINOM_FACT)) THEN ASM_SIMP_TAC[DIVIDES_FACT_PRIME; PRIME_DIVPROD_EQ; SUB_ADD; LT_IMP_LE] THEN ASM_REWRITE_TAC[GSYM NOT_LT; LT_REFL] THEN ASM_SIMP_TAC[ARITH_RULE `0 < n /\ n < p ==> p - n < p`]);; let DIVIDES_NSUM = prove (`!m n. (!i. m <= i /\ i <= n ==> p divides f(i)) ==> p divides nsum(m..n) f`, GEN_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[NSUM_CLAUSES_NUMSEG] THEN ASM_MESON_TAC[LE; LE_TRANS; DIVIDES_0; DIVIDES_ADD; LE_REFL]);; let FLT_LEMMA = prove (`!p a b. prime p ==> ((a + b) EXP p == a EXP p + b EXP p) (mod p)`, REPEAT STRIP_TAC THEN REWRITE_TAC[BINOMIAL_THEOREM] THEN SUBGOAL_THEN `1 <= p /\ 0 < p` STRIP_ASSUME_TAC THENL [FIRST_ASSUM(MP_TAC o MATCH_MP PRIME_IMP_NZ) THEN ARITH_TAC; ALL_TAC] THEN ASM_SIMP_TAC[NSUM_CLAUSES_LEFT; LE_0; ARITH; NSUM_CLAUSES_RIGHT] THEN REWRITE_TAC[SUB_0; SUB_REFL; EXP; binom; BINOM_REFL; MULT_CLAUSES] THEN GEN_REWRITE_TAC LAND_CONV [ARITH_RULE `a + b = (b + 0) + a`] THEN REPEAT(MATCH_MP_TAC CONG_ADD THEN REWRITE_TAC[CONG_REFL]) THEN REWRITE_TAC[CONG_0] THEN MATCH_MP_TAC DIVIDES_NSUM THEN ASM_MESON_TAC[DIVIDES_RMUL; DIVIDES_BINOM_PRIME; ARITH_RULE `0 < p /\ 1 <= i /\ i <= p - 1 ==> 0 < i /\ i < p`]);; let FERMAT_LITTLE = prove (`!p a. prime p ==> (a EXP p == a) (mod p)`, GEN_TAC THEN REWRITE_TAC[RIGHT_FORALL_IMP_THM] THEN DISCH_TAC THEN INDUCT_TAC THENL [ASM_MESON_TAC[EXP_EQ_0; CONG_REFL; PRIME_0]; ASM_MESON_TAC[ADD1; FLT_LEMMA; EXP_ONE; CONG_ADD; CONG_TRANS; CONG_REFL]]);; let FERMAT_LITTLE_COPRIME = prove (`!p a. prime p /\ coprime(a,p) ==> (a EXP (p - 1) == 1) (mod p)`, REPEAT STRIP_TAC THEN MATCH_MP_TAC CONG_MULT_LCANCEL THEN EXISTS_TAC `a:num` THEN ASM_REWRITE_TAC[GSYM(CONJUNCT2 EXP)] THEN ASM_SIMP_TAC[PRIME_IMP_NZ; ARITH_RULE `~(p = 0) ==> SUC(p - 1) = p`] THEN ASM_SIMP_TAC[FERMAT_LITTLE; MULT_CLAUSES]);; let FERMAT_LITTLE_VARIANT = prove (`!p a. prime p ==> (a EXP (1 + m * (p - 1)) == a) (mod p)`, REPEAT STRIP_TAC THEN FIRST_ASSUM(DISJ_CASES_TAC o SPEC `a:num` o MATCH_MP PRIME_COPRIME_STRONG) THENL [ASM_MESON_TAC[CONG_TRIVIAL; ADD_AC; ADD1; DIVIDES_REXP_SUC]; ALL_TAC] THEN GEN_REWRITE_TAC LAND_CONV [ARITH_RULE `a = a * 1`] THEN REWRITE_TAC[EXP_ADD; EXP_1] THEN MATCH_MP_TAC CONG_MULT THEN REWRITE_TAC[GSYM EXP_EXP; CONG_REFL] THEN ASM_MESON_TAC[COPRIME_SYM; COPRIME_EXP; PHI_PRIME; FERMAT_LITTLE_COPRIME]);; let RSA = prove (`prime p /\ prime q /\ ~(p = q) /\ (d * e == 1) (mod ((p - 1) * (q - 1))) /\ plaintext < p * q /\ (ciphertext = (plaintext EXP e) MOD (p * q)) ==> (plaintext = (ciphertext EXP d) MOD (p * q))`, REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN ASM_SIMP_TAC[MOD_EXP_MOD; MULT_EQ_0; PRIME_IMP_NZ; EXP_EXP] THEN SUBGOAL_THEN `(plaintext == plaintext EXP (e * d)) (mod (p * q))` MP_TAC THENL [ALL_TAC; ASM_SIMP_TAC[CONG; MULT_EQ_0; PRIME_IMP_NZ; MOD_LT]] THEN GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [MULT_SYM] THEN FIRST_X_ASSUM(DISJ_CASES_TAC o GEN_REWRITE_RULE I [CONG_TO_1]) THENL [ASM_MESON_TAC[MULT_EQ_1; ARITH_RULE `p - 1 = 1 <=> p = 2`]; ALL_TAC] THEN MATCH_MP_TAC CONG_CHINESE THEN ASM_SIMP_TAC[DISTINCT_PRIME_COPRIME] THEN ASM_MESON_TAC[FERMAT_LITTLE_VARIANT; MULT_AC; CONG_SYM]);;