From 3c597e8c05da913b8c60fbdc613ad890ca16014e Mon Sep 17 00:00:00 2001 From: Ethan Kharitonov Date: Tue, 28 Apr 2026 14:47:23 -0700 Subject: [PATCH 1/2] [cleanup] Add .DS_Store and .idea/ to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 7507fc26..805416bc 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ dependencies/ # Other Conformance_Testing/ +.DS_Store +.idea/ From 8e01edde9fc8493889b1d23e5353b43d97f1dfa5 Mon Sep 17 00:00:00 2001 From: Ethan Kharitonov Date: Tue, 28 Apr 2026 14:48:11 -0700 Subject: [PATCH 2/2] [feat] examples: Add number-theory related uRust examples --- Micro_Rust_Examples/Number_Theory.thy | 426 ++++++++++++++++++++++++++ Micro_Rust_Examples/ROOT | 2 + 2 files changed, 428 insertions(+) create mode 100644 Micro_Rust_Examples/Number_Theory.thy diff --git a/Micro_Rust_Examples/Number_Theory.thy b/Micro_Rust_Examples/Number_Theory.thy new file mode 100644 index 00000000..5b90739a --- /dev/null +++ b/Micro_Rust_Examples/Number_Theory.thy @@ -0,0 +1,426 @@ +(* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + SPDX-License-Identifier: MIT *) + +theory Number_Theory + imports Micro_Rust_Std_Lib.StdLib_All "HOL-Number_Theory.Totient" +begin + +section\Number Theory\ + +locale number_theory = + reference reference_types + + ref_word: reference_allocatable reference_types _ _ _ _ _ _ _ word_prism + + ref_nat: reference_allocatable reference_types _ _ _ _ _ _ _ nat_prism + + ref_int: reference_allocatable reference_types _ _ _ _ _ _ _ int_prism + for reference_types :: \'s::{sepalg} \ 'addr \ 'gv \ 'abort \ 'i prompt \ 'o prompt_output \ unit\ + and word_prism :: \('gv, 'w::len word) prism\ + and nat_prism :: \('gv, nat) prism\ + and int_prism :: \('gv, int) prism\ +begin + +adhoc_overloading store_reference_const \ ref_word.new +adhoc_overloading store_reference_const \ ref_nat.new +adhoc_overloading store_reference_const \ ref_int.new +adhoc_overloading store_update_const \ update_fun +adhoc_overloading urust_add \ \bind2 (lift_exp2 (plus :: nat \ nat \ nat))\ + +abbreviation fully_owns where \fully_owns r v \ \g. r \\\\ g\v\ + +subsection\Fibonacci\ + +fun fib :: \nat \ nat\ where + \fib 0 = 0\ +| \fib (Suc 0) = 1\ +| \fib (Suc (Suc n)) = fib n + fib (Suc n)\ + +definition fib_prog where + \fib_prog n \ FunctionBody \ + let mut a = \0 :: nat\; + let mut b = \1 :: nat\; + for i in 0..n { + let old_a = *a; + let old_b = *b; + a = old_b; + b = old_a + old_b + }; + *a + \\ + +definition fib_contract where + \fib_contract n \ + make_function_contract + (can_alloc_reference) + (\ret. \ret = fib (unat n)\ \ can_alloc_reference)\ +ucincl_auto fib_contract + +lemma fib_spec: + shows \\; fib_prog n \\<^sub>F fib_contract n\ + apply (crush_boot f: fib_prog_def contract: fib_contract_def) + apply crush_base + subgoal for a_ref b_ref + apply (ucincl_discharge\ + rule_tac + INV=\\_ i. fully_owns a_ref (fib i) \ fully_owns b_ref (fib (i + 1))\ and + \=\\_. \False\\ and + \=\\_. \False\\ + in wp_raw_for_loop_framedI' + \) + apply (crush_base simp add: unat_of_nat_eq le_unat_uoi') + done + done + +subsection\GCD\ + +definition gcd_prog where + \gcd_prog a b \ FunctionBody \ + let mut x = \a :: nat\; + let mut y = \b :: nat\; + #[fuel(\\a + b\)] while (*y != 0) { + let xv = *x; + let yv = *y; + x = yv; + y = \xv mod yv\ + }; + *x + \\ + +definition gcd_contract where + \gcd_contract a b \ + make_function_contract + (can_alloc_reference) + (\ret. \ret = gcd a b\ \ can_alloc_reference)\ +ucincl_auto gcd_contract + +lemma gcd_spec: + shows \\; gcd_prog a b \\<^sub>F gcd_contract a b\ + apply (crush_boot f: gcd_prog_def contract: gcd_contract_def) + apply crush_base + subgoal for x_ref y_ref + apply (ucincl_discharge\ + rule_tac + INV=\\k. \ xv yv. fully_owns x_ref xv \ fully_owns y_ref yv \ \gcd xv yv = gcd a b \ yv \ k\\ and + INV'=\\k. \ xv yv. fully_owns x_ref xv \ fully_owns y_ref yv \ \gcd xv yv = gcd a b \ 0 < yv \ yv \ k + 1\\ and + \=\\_. \False\\ and + \=\\_. \False\\ + in wp_bounded_while_framedI + \) + apply crush_base + subgoal for k _ _ r ra + using mod_less_divisor[of ra r] by linarith + subgoal by (simp add: gcd.commute) + done + done + +subsection\Extended GCD\ + +definition egcd_prog where + \egcd_prog (a :: int) b \ FunctionBody \ + let mut old_remainder = \a\; + let mut remainder = \b\; + + let mut old_a_coef = \1 :: int\; + let mut a_coef = \0 :: int\; + + let mut old_b_coef = \0 :: int\; + let mut b_coef = \1 :: int\; + #[fuel(\\nat a + nat b\)] while (*remainder > \0 :: int\) { + let old_remainder_val = *old_remainder; + let remainder_val = *remainder; + let quotient = \old_remainder_val div remainder_val\; + old_remainder = remainder_val; + remainder = \old_remainder_val - quotient * remainder_val\; + + let old_a_coef_val = *old_a_coef; + let a_coef_val = *a_coef; + old_a_coef = a_coef_val; + a_coef = \old_a_coef_val - quotient * a_coef_val\; + + let old_b_coef_val = *old_b_coef; + let b_coef_val = *b_coef; + old_b_coef = b_coef_val; + b_coef = \old_b_coef_val - quotient * b_coef_val\ + }; + + let final_remainder = *old_remainder; + let final_a_coef = *old_a_coef; + let final_b_coef = *old_b_coef; + + (final_remainder, final_a_coef, final_b_coef) + \\ + +definition egcd_contract where + \egcd_contract (a :: int) b \ + make_function_contract + (\0 \ a \ 0 \ b\ \ can_alloc_reference) + (\(g, s, t, _). \g = gcd a b \ a * s + b * t = g\ \ can_alloc_reference)\ +ucincl_proof egcd_contract by (clarsimp split: prod.splits; ucincl_solve) + +\ \Heap layout + Bezout identity + gcd preservation\ +abbreviation egcd_inv where + \egcd_inv a b old_remainder_ref remainder_ref old_a_coef_ref a_coef_ref old_b_coef_ref b_coef_ref + old_remainder remainder old_a_coef a_coef old_b_coef b_coef \ + fully_owns old_remainder_ref old_remainder \ + fully_owns remainder_ref remainder \ + fully_owns old_a_coef_ref old_a_coef \ + fully_owns a_coef_ref a_coef \ + fully_owns old_b_coef_ref old_b_coef \ + fully_owns b_coef_ref b_coef \ + \a * old_a_coef + b * old_b_coef = old_remainder \ + a * a_coef + b * b_coef = remainder \ + 0 \ old_remainder \ 0 \ remainder \ + gcd old_remainder remainder = gcd a b\\ + +lemma egcd_spec: + shows \\; egcd_prog a b \\<^sub>F egcd_contract a b\ + apply (crush_boot f: egcd_prog_def contract: egcd_contract_def) + apply crush_base + subgoal for old_remainder_ref remainder_ref old_a_coef_ref a_coef_ref old_b_coef_ref b_coef_ref + apply (ucincl_discharge\ + rule_tac + INV=\\k. \ old_remainder remainder old_a_coef a_coef old_b_coef b_coef. + egcd_inv a b old_remainder_ref remainder_ref old_a_coef_ref a_coef_ref old_b_coef_ref b_coef_ref old_remainder remainder old_a_coef a_coef old_b_coef b_coef \ + \remainder \ int k\\ and + INV'=\\k. \ old_remainder remainder old_a_coef a_coef old_b_coef b_coef. + egcd_inv a b old_remainder_ref remainder_ref old_a_coef_ref a_coef_ref old_b_coef_ref b_coef_ref old_remainder remainder old_a_coef a_coef old_b_coef b_coef \ + \0 < remainder \ remainder \ int k + 1\\ and + \=\\_. \False\\ and + \=\\_. \False\\ + in wp_bounded_while_framedI + \) + apply crush_base + subgoal for k _ _ _ _ _ _ r ra rb rc + apply (simp add: minus_div_mult_eq_mod) + using pos_mod_bound[of \a * ra + b * rc\ \a * r + b * rb\] + by linarith + subgoal + by (simp add: minus_div_mult_eq_mod) (metis gcd.commute gcd_red_int) + subgoal + by (metis minus_div_mult_eq_mod pos_mod_sign diff_ge_0_iff_ge) + subgoal + by (simp add: algebra_simps) + done + done + +subsection\Euler's Totient\ + +definition totient_prog where + \totient_prog n \ FunctionBody \ + let mut count = \0 :: nat\; + for i in 0..n { + let g = gcd_prog(\unat i + 1\, \unat n\); + if (\g = 1\) { + count = *count + 1 + } + }; + *count + \\ + +definition totient_contract where + \totient_contract n \ + make_function_contract + (can_alloc_reference) + (\ret. \ret = totient (unat n)\ \ can_alloc_reference)\ +ucincl_auto totient_contract + +\ \\<^verbatim>\|{k in {1..i+1}. P(k)}| = |{k in {1..i}. P(k)}| + (if P(i+1) then 1 else 0)\\ +lemma card_coprime_step: + \card {k. Suc 0 \ k \ k \ Suc i \ P k} = + card {k. Suc 0 \ k \ k \ i \ P k} + (if P (Suc i) then 1 else 0)\ +proof - + have \{k. Suc 0 \ k \ k \ Suc i \ P k} = + {k. Suc 0 \ k \ k \ i \ P k} \ (if P (Suc i) then {Suc i} else {})\ + by (auto simp: le_Suc_eq) + thus ?thesis by (simp add: card_insert_if finite_subset[of _ "{0..i}"]) +qed + +lemma totient_spec: + shows \\; totient_prog n \\<^sub>F totient_contract n\ + apply (simp only: totient_contract_def totient_def totatives_def + atLeastSucAtMost_greaterThanAtMost) + apply (crush_boot f: totient_prog_def) + apply crush_base + subgoal for count_ref + apply (ucincl_discharge\ + rule_tac + INV=\\_ i. fully_owns count_ref (card {k \ {1..i}. coprime k (unat n)}) \ can_alloc_reference\ and + \=\\_. \False\\ and + \=\\_. \False\\ + in wp_raw_for_loop_framedI' + \) + apply (crush_base specs add: gcd_spec contracts add: gcd_contract_def simp add: unat_of_nat_eq le_unat_uoi') + subgoal by (auto simp: le_Suc_eq coprime_iff_gcd_eq_1 intro: arg_cong[of _ _ card]) + subgoal by (simp add: card_coprime_step coprime_iff_gcd_eq_1) + subgoal by (auto intro: arg_cong[of _ _ card]) + done +done + +subsection\Modular Exponentiation\ + +definition mod_exp_prog where + \mod_exp_prog base ex m \ FunctionBody \ + let mut b = \base :: nat\; + let mut e = \ex :: nat\; + let mut acc = \1 :: nat\; + + #[fuel(\\ex\)] while (*e != 0) { + let ev = *e; + let bv = *b; + let av = *acc; + + if (\ev mod 2 = 1\) { + acc = \av * bv mod m\ + }; + + b = \bv * bv mod m\; + e = \ev div 2\ + }; + + *acc + \\ + +definition mod_exp_contract where + \mod_exp_contract base ex m \ + make_function_contract + (\m \ 1\ \ can_alloc_reference) + (\ret. \ret = base ^ ex mod m\ \ can_alloc_reference)\ +ucincl_auto mod_exp_contract + +lemma sq_pow_even: \even n \ (x * x) ^ (n div 2) = x ^ n\ + for x :: nat +proof (elim evenE) + fix k assume \n = 2 * k\ + thus \(x * x) ^ (n div 2) = x ^ n\ + by (simp add: power_mult_distrib mult_2 flip: power_add) +qed + +lemma sq_pow_odd: \n mod 2 = Suc 0 \ x * (x * x) ^ (n div 2) = x ^ n\ + for x :: nat +proof - + assume \n mod 2 = Suc 0\ + hence nk: \n = Suc (2 * (n div 2))\ by arith + show ?thesis + by (subst nk) (simp add: power_mult_distrib mult_2 power_add) +qed + +lemma mod_exp_spec: + shows \\; mod_exp_prog base ex m \\<^sub>F mod_exp_contract base ex m\ + apply (crush_boot f: mod_exp_prog_def contract: mod_exp_contract_def) + apply crush_base + subgoal for b_ref e_ref acc_ref + apply (ucincl_discharge\ + rule_tac + INV=\\k. \ bv ev av. fully_owns b_ref bv \ fully_owns e_ref ev \ fully_owns acc_ref av \ \(av * bv ^ ev) mod m = base ^ ex mod m \ (0 < m \ av < m) \ ev \ k\\ and + INV'=\\k. \ bv ev av. fully_owns b_ref bv \ fully_owns e_ref ev \ fully_owns acc_ref av \ \(av * bv ^ ev) mod m = base ^ ex mod m \ (0 < m \ av < m) \ 0 < ev \ ev \ k + 1\\ and + \=\\_. \False\\ and + \=\\_. \False\\ + in wp_bounded_while_framedI + \) + apply crush_base + subgoal by linarith + subgoal for k _ _ _ ev bv av + using sq_pow_even[of ev bv] + by (metis mod_mult_right_eq power_mod) + subgoal by linarith + subgoal for k _ _ _ ev bv av + using sq_pow_odd[of ev bv] + by (simp add: mod_mult_left_eq mult.assoc) (metis mod_mult_right_eq power_mod) + subgoal by auto + done +done + +subsection\Primality Testing\ + +definition is_prime_prog where + \is_prime_prog n \ FunctionBody \ + if (\unat n < 2\) { + return False; + }; + + for i in 0..n { + if (\(unat i + 2) * (unat i + 2) \ unat n \ unat n mod (unat i + 2) = 0\) { + return False; + } + }; + + True + \\ + +definition is_prime_contract where + \is_prime_contract n \ + make_function_contract + (can_alloc_reference) + (\ret. \ret = prime (unat n)\ \ can_alloc_reference)\ +ucincl_auto is_prime_contract + +lemma primeI_no_small_divisor: + assumes \1 < (n :: nat)\ \\d \ {2..n}. d\<^sup>2 \ n \ \ d dvd n\ + shows \prime n\ +proof (rule ccontr) + assume np: \\ prime n\ + from prime_factor_nat[of n] assms(1) obtain p where p: \prime p\ \p dvd n\ by auto + let ?q = \n div p\ + have n_eq: \n = p * ?q\ using p(2) by simp + have p2: \2 \ p\ using p(1) prime_ge_2_nat by simp + have q_nz: \?q \ 0\ using n_eq assms(1) by (cases ?q) auto + have q_n1: \?q \ 1\ using n_eq p(1) np by auto + have q2: \2 \ ?q\ using q_nz q_n1 by linarith + define d where \d = min p ?q\ + have \d\<^sup>2 \ p * ?q\ unfolding d_def power2_eq_square + by (simp add: min_def mult_le_mono1 mult_le_mono2) + moreover have \d dvd n\ unfolding d_def using p(2) n_eq by (auto simp: min_def dvd_div_iff_mult) + moreover have \d \ {2..n}\ + unfolding d_def using p2 q2 dvd_imp_le[OF p(2)] div_le_dividend[of n p] assms(1) by (auto simp: min_def) + ultimately show False using assms(2) n_eq by auto +qed + +lemmas prime_natD = prime_nat_iff[THEN iffD1, THEN conjunct2, rule_format] + +\ \Extending the no-small-divisor range by one\ +lemma no_small_divisor_step: + assumes inv: \\d \ {2..i+1}. d\<^sup>2 \ n \ \ d dvd n\ + and body: \\ ((i+2)\<^sup>2 \ n \ (i+2) dvd n)\ + shows \\d \ {2..i+2}. d\<^sup>2 \ n \ \ d dvd (n :: nat)\ +proof (intro ballI impI notI) + fix d assume \d \ {2..i+2}\ \d\<^sup>2 \ n\ \d dvd n\ + hence \d \ {2..i+1} \ d = i+2\ by auto + thus False + proof + assume \d \ {2..i+1}\ + with inv \d\<^sup>2 \ n\ \d dvd n\ show False by auto + next + assume \d = i+2\ + with body \d\<^sup>2 \ n\ \d dvd n\ show False by auto + qed +qed + +lemma is_prime_spec: + shows \\; is_prime_prog n \\<^sub>F is_prime_contract n\ + apply (crush_boot f: is_prime_prog_def contract: is_prime_contract_def) + apply crush_base + subgoal + apply (ucincl_discharge\ + rule_tac + INV=\\_ i. \\d \ {2..i + 1}. d\<^sup>2 \ unat n \ \ d dvd unat n\ \ can_alloc_reference\ and + \=\\ret. \ret = False \ \ prime (unat n)\ \ can_alloc_reference\ and + \=\\_. \False\\ + in wp_raw_for_loop_framedI' + \) + apply crush_base + subgoal for i d + apply (frule le_unat_uoi', simp) + apply (drule no_small_divisor_step[of i \unat n\, simplified]) + apply (simp add: power2_eq_square algebra_simps dvd_eq_mod_eq_0) + by auto + subgoal for i + apply (frule le_unat_uoi') + apply simp + apply (drule(1) prime_natD) + by (simp add: algebra_simps) + subgoal using primeI_no_small_divisor by auto + done + subgoal using not_prime_0 not_prime_1 by (auto simp: less_2_cases_iff unat_eq_zero) + done + +end + +end diff --git a/Micro_Rust_Examples/ROOT b/Micro_Rust_Examples/ROOT index d36542d6..1b3f0fcf 100644 --- a/Micro_Rust_Examples/ROOT +++ b/Micro_Rust_Examples/ROOT @@ -2,6 +2,7 @@ session Micro_Rust_Examples = HOL + options [document = pdf, document_output = "output"] sessions "HOL-Library" + "HOL-Number_Theory" Separation_Lenses Shallow_Micro_Rust Shallow_Separation_Logic @@ -21,6 +22,7 @@ session Micro_Rust_Examples = HOL + Linked_List_Executable_Physical_Memory Reference_Examples Showcase + Number_Theory MLKEM_Parameters MLKEM_Specification MLKEM_Zq