Theory Rivest
subsection‹Rivest Commitment Scheme›
text‹The Rivest commitment scheme was first introduced in \<^cite>‹"rivest1999"›. We note however the original
scheme did not allow for perfect hiding. This was pointed out by Blundo and Masucci in \<^cite>‹"DBLP:journals/dcc/BlundoMSW02"›
who alightly ammended the commitment scheme so that is provided perfect hiding.
The Rivest commitment scheme uses a trusted initialiser to provide correlated randomness to the two parties
before an execution of the protocol. In our framework we set these as keys that held by the respective parties.›
theory Rivest imports
Commitment_Schemes
"HOL-Number_Theory.Cong"
CryptHOL.CryptHOL
Cyclic_Group_Ext
Discrete_Log
Number_Theory_Aux
Uniform_Sampling
begin
locale rivest =
fixes q :: nat
assumes prime_q: "prime q"
begin
lemma q_gt_0 [simp]: "q > 0"
by (simp add: prime_q prime_gt_0_nat)
type_synonym ck = "nat × nat"
type_synonym vk = "nat × nat"
type_synonym plain = "nat"
type_synonym commit = "nat"
type_synonym "opening" = "nat × nat"
definition key_gen :: "(ck × vk) spmf"
where
"key_gen = do {
a :: nat ← sample_uniform q;
b :: nat ← sample_uniform q;
x1 :: nat ← sample_uniform q;
let y1 = (a * x1 + b) mod q;
return_spmf ((a,b), (x1,y1))}"
definition commit :: "ck ⇒ plain ⇒ (commit × opening) spmf"
where
"commit ck m = do {
let (a,b) = ck;
return_spmf ((m + a) mod q, (a,b))}"
fun verify :: "vk ⇒ plain ⇒ commit ⇒ opening ⇒ bool"
where
"verify (x1,y1) m c (a,b) = (((c = (m + a) mod q)) ∧ (y1 = (a * x1 + b) mod q))"
definition valid_msg :: "plain ⇒ bool"
where "valid_msg msg ≡ msg ∈ {..< q}"
sublocale rivest_commit: abstract_commitment key_gen commit verify valid_msg .
lemma abstract_correct: "rivest_commit.correct"
unfolding abstract_commitment.correct_def abstract_commitment.correct_game_def
by(simp add: key_gen_def commit_def bind_spmf_const lossless_weight_spmfD)
lemma rivest_hiding: "(spmf (rivest_commit.hiding_game_ind_cpa 𝒜) True - 1/2 = 0)"
including monad_normalisation
proof-
note [simp] = Let_def split_def
obtain 𝒜1 𝒜2 where [simp]: "𝒜 = (𝒜1, 𝒜2)" by(cases 𝒜)
have "rivest_commit.hiding_game_ind_cpa (𝒜1, 𝒜2) = TRY do {
a :: nat ← sample_uniform q;
x1 :: nat ← sample_uniform q;
y1 ← map_spmf (λ b. (a * x1 + b) mod q) (sample_uniform q);
((m0, m1), σ) ← 𝒜1 (x1,y1);
_ :: unit ← assert_spmf (valid_msg m0 ∧ valid_msg m1);
d ← coin_spmf;
let c = ((if d then m0 else m1) + a) mod q;
b' ← 𝒜2 c σ;
return_spmf (b' = d)} ELSE coin_spmf"
unfolding abstract_commitment.hiding_game_ind_cpa_def
by(simp add: commit_def key_gen_def o_def bind_map_spmf)
also have "... = TRY do {
a :: nat ← sample_uniform q;
x1 :: nat ← sample_uniform q;
y1 ← sample_uniform q;
((m0, m1), σ) ← 𝒜1 (x1,y1);
_ :: unit ← assert_spmf (valid_msg m0 ∧ valid_msg m1);
d ← coin_spmf;
let c = ((if d then m0 else m1) + a) mod q;
b' ← 𝒜2 c σ;
return_spmf (b' = d)} ELSE coin_spmf"
by(simp add: samp_uni_plus_one_time_pad)
also have "... = TRY do {
x1 :: nat ← sample_uniform q;
y1 ← sample_uniform q;
((m0, m1), σ) ← 𝒜1 (x1,y1);
_ :: unit ← assert_spmf (valid_msg m0 ∧ valid_msg m1);
d ← coin_spmf;
c ← map_spmf (λ a. ((if d then m0 else m1) + a) mod q) (sample_uniform q);
b' ← 𝒜2 c σ;
return_spmf (b' = d)} ELSE coin_spmf"
by(simp add: o_def bind_map_spmf)
also have "... = TRY do {
x1 :: nat ← sample_uniform q;
y1 ← sample_uniform q;
((m0, m1), σ) ← 𝒜1 (x1,y1);
_ :: unit ← assert_spmf (valid_msg m0 ∧ valid_msg m1);
d ← coin_spmf;
c ← sample_uniform q;
b' :: bool ← 𝒜2 c σ;
return_spmf (b' = d)} ELSE coin_spmf"
by(simp add: samp_uni_plus_one_time_pad)
also have "... = TRY do {
x1 :: nat ← sample_uniform q;
y1 ← sample_uniform q;
((m0, m1), σ) ← 𝒜1 (x1,y1);
_ :: unit ← assert_spmf (valid_msg m0 ∧ valid_msg m1);
c :: nat ← sample_uniform q;
guess :: bool ← 𝒜2 c σ;
map_spmf((=) guess) coin_spmf} ELSE coin_spmf"
by(simp add: map_spmf_conv_bind_spmf)
also have "... = coin_spmf"
by(simp add: map_eq_const_coin_spmf bind_spmf_const try_bind_spmf_lossless2'
scale_bind_spmf weight_spmf_le_1 scale_scale_spmf)
ultimately show ?thesis
by(simp add: spmf_of_set)
qed
lemma rivest_perfect_hiding: "rivest_commit.perfect_hiding_ind_cpa 𝒜"
unfolding abstract_commitment.perfect_hiding_ind_cpa_def abstract_commitment.hiding_advantage_ind_cpa_def
by(simp add: rivest_hiding)
lemma samp_uni_break':
assumes fst_cond: "m ≠ m' ∧ valid_msg m ∧ valid_msg m'"
and c: "c = (m + a) mod q ∧ y1 = (a * x1 + b) mod q"
and c': "c = (m' + a') mod q ∧ y1 = (a' * x1 + b') mod q"
and x1: "x1 < q"
shows "x1 = (if (a mod q > a' mod q) then nat ((int b'- int b) * (inverse (nat ((int a mod q - int a' mod q) mod q)) q) mod q) else
nat ((int b- int b') * (inverse (nat ((int a' mod q - int a mod q) mod q)) q) mod q))"
proof-
have m: "m < q ∧ m' < q" using fst_cond valid_msg_def by simp
have a_a': "¬ [a = a'] (mod q)"
proof-
have "[m + a = m' + a'] (mod q)"
using assms cong_def by blast
thus ?thesis
by (metis m fst_cond c c' add.commute cong_less_modulus_unique_nat cong_add_rcancel_nat cong_mod_right)
qed
have cong_y1: "[int a * int x1 + int b = int a' * int x1 + int b'] (mod q)"
by (metis c c' cong_def Num.of_nat_simps(4) Num.of_nat_simps(5) cong_int_iff)
show ?thesis
proof (cases "a mod q > a' mod q")
case True
moreover have ‹((int a mod q - int a' mod q) mod q) ≠ 0›
by (metis True comm_monoid_add_class.add_0 diff_add_cancel mod_add_left_eq mod_diff_eq nat_mod_as_int order_less_irrefl)
moreover have "((int a mod q - int a' mod q) mod q) < q" by simp
ultimately have ‹coprime (nat ((int a mod q - int a' mod q) mod q)) q›
using prime_field [of q ‹nat ((int a mod int q - int a' mod int q) mod int q)›] prime_q
by (simp flip: of_nat_mod of_nat_diff)
then have gcd: "gcd (nat ((int a mod q - int a' mod q) mod q)) q = 1"
by simp
hence "[int a * int x1 - int a' * int x1 = int b'- int b] (mod q)"
by (smt cong_diff_iff_cong_0 cong_y1 cong_diff cong_diff)
hence "[int a mod q * int x1 - int a' mod q * int x1 = int b'- int b] (mod q)"
proof -
have "[int x1 * (int a mod int q - int a' mod int q) = int x1 * (int a - int a')] (mod int q)"
by (meson cong_def cong_mult cong_refl mod_diff_eq)
then show ?thesis
by (metis (no_types, opaque_lifting) Groups.mult_ac(2) ‹[int a * int x1 - int a' * int x1 = int b' - int b] (mod int q)› cong_def mod_diff_left_eq mod_diff_right_eq mod_mult_right_eq)
qed
hence "[int x1 * (int a mod q - int a' mod q) = int b'- int b] (mod q)"
by(metis int_distrib(3) mult.commute)
hence "[int x1 * (int a mod q - int a' mod q) mod q = int b'- int b] (mod q)"
using cong_def by simp
hence "[int x1 * nat ((int a mod q - int a' mod q) mod q) = int b'- int b] (mod q)"
by (simp add: True cong_def mod_mult_right_eq)
hence "[int x1 * nat ((int a mod q - int a' mod q) mod q) * inverse (nat ((int a mod q - int a' mod q) mod q)) q
= (int b'- int b) * inverse (nat ((int a mod q - int a' mod q) mod q)) q] (mod q)"
using cong_scalar_right by blast
hence "[int x1 * (nat ((int a mod q - int a' mod q) mod q) * inverse (nat ((int a mod q - int a' mod q) mod q)) q)
= (int b'- int b) * inverse (nat ((int a mod q - int a' mod q) mod q)) q] (mod q)"
by (simp add: more_arith_simps(11))
hence "[int x1 * 1 = (int b'- int b) * inverse (nat ((int a mod q - int a' mod q) mod q)) q] (mod q)"
using inverse gcd
by (meson cong_scalar_left cong_sym_eq cong_trans)
hence "[int x1 = (int b'- int b) * inverse (nat ((int a mod q - int a' mod q) mod q)) q] (mod q)"
by simp
hence "int x1 mod q = ((int b'- int b) * inverse (nat ((int a mod q - int a' mod q) mod q)) q) mod q"
using cong_def by fast
thus ?thesis using x1 True by simp
next
case False
hence aa': "a mod q < a' mod q"
using a_a' cong_refl nat_neq_iff
by (simp add: cong_def)
moreover have "((int a' mod q - int a mod q) mod q) ≠ 0"
by (metis aa' comm_monoid_add_class.add_0 diff_add_cancel mod_add_left_eq mod_diff_eq nat_mod_as_int order_less_irrefl)
moreover have "((int a' mod q - int a mod q) mod q) < q" by simp
ultimately have ‹coprime (nat ((int a' mod q - int a mod q) mod q)) q›
using prime_field [of q ‹nat ((int a' mod int q - int a mod int q) mod int q)›] prime_q
by (simp flip: of_nat_mod of_nat_diff)
then have gcd: "gcd (nat ((int a' mod q - int a mod q) mod q)) q = 1"
by simp
have "[int b - int b' = int a' * int x1 - int a * int x1] (mod q)"
by (smt cong_diff_iff_cong_0 cong_y1 cong_diff cong_diff)
hence "[int b - int b' = int x1 * (int a' - int a)] (mod q)"
using int_distrib mult.commute by metis
hence "[int b - int b' = int x1 * (int a' mod q - int a mod q)] (mod q)"
by (metis (no_types, lifting) cong_def mod_diff_eq mod_mult_right_eq)
hence "[int b - int b' = int x1 * (int a' mod q - int a mod q) mod q] (mod q)"
using cong_def by simp
hence "[(int b - int b') * inverse (nat ((int a' mod q - int a mod q) mod q)) q
= int x1 * (int a' mod q - int a mod q) mod q * inverse (nat ((int a' mod q - int a mod q) mod q)) q ] (mod q)"
using cong_scalar_right by blast
hence "[(int b - int b') * inverse (nat ((int a' mod q - int a mod q) mod q)) q
= int x1 * ((int a' mod q - int a mod q) mod q * inverse (nat ((int a' mod q - int a mod q) mod q)) q)] (mod q)"
by (metis (mono_tags, lifting) cong_def mod_mult_left_eq mod_mult_right_eq more_arith_simps(11))
hence *: "[int x1 * ((int a' mod q - int a mod q) mod q * inverse (nat ((int a' mod q - int a mod q) mod q)) q)
= (int b - int b') * inverse (nat ((int a' mod q - int a mod q) mod q)) q] (mod q)"
using cong_sym_eq by auto
hence "[int x1 * 1 = (int b - int b') * inverse (nat ((int a' mod q - int a mod q) mod q)) q] (mod q)"
proof -
have "[(int a' mod int q - int a mod int q) mod int q * Number_Theory_Aux.inverse (nat ((int a' mod int q - int a mod int q) mod int q)) q = 1] (mod int q)"
using inverse [of ‹nat ((int a' mod int q - int a mod int q) mod int q)› q, OF gcd]
by simp
then show ?thesis
by (meson * cong_scalar_left cong_sym_eq cong_trans)
qed
hence "[int x1 = (int b - int b') * inverse (nat ((int a' mod q - int a mod q) mod q)) q] (mod q)"
by simp
hence "int x1 mod q = (int b - int b') * (inverse (nat ((int a' mod q - int a mod q) mod q)) q) mod q"
using cong_def by auto
thus ?thesis using x1 aa' by simp
qed
qed
lemma samp_uni_spmf_mod_q:
shows "spmf (sample_uniform q) (x mod q) = 1/q"
proof-
have "indicator {..< q} (x mod q) = 1"
using q_gt_0 by auto
moreover have "real (card {..< q}) = q" by simp
ultimately show ?thesis
by(auto simp add: spmf_of_set sample_uniform_def)
qed
lemma spmf_samp_uni_eq_return_bool_mod:
shows "spmf (do {
x1 ← sample_uniform q;
return_spmf (int x1 = y mod q)}) True = 1/q"
proof-
have "spmf (do {
x1 ← sample_uniform q;
return_spmf (x1 = y mod q)}) True = spmf (sample_uniform q ⤜ (λ x1. return_spmf x1)) (y mod q)"
apply(simp only: spmf_bind)
apply(rule Bochner_Integration.integral_cong[OF refl])+
proof -
fix x :: nat
have "y mod q = x ⟶ indicator {True} (x = (y mod q)) = (indicator {(y mod q)} x::real)"
by simp
then have "indicator {True} (x = y mod q) = (indicator {y mod q} x::real)"
by fastforce
then show "spmf (return_spmf (x = y mod q)) True = spmf (return_spmf x) (y mod q)"
by (metis pmf_return spmf_of_pmf_return_pmf spmf_spmf_of_pmf)
qed
thus ?thesis using samp_uni_spmf_mod_q by simp
qed
lemma bind_game_le_inv_q:
shows "spmf (rivest_commit.bind_game 𝒜) True ≤ 1 / q"
proof -
let ?eq = "λa a' b b'. (=)
(if (a mod q > a' mod q) then nat ((int b'- int b) * (inverse (nat ((int a mod q - int a' mod q) mod q)) q) mod q)
else nat ((int b - int b') * (inverse (nat ((int a' mod q - int a mod q) mod q)) q) mod q))"
have "spmf (rivest_commit.bind_game 𝒜) True = spmf (do {
(ck,(x1,y1)) ← key_gen;
(c, m, (a,b), m', (a',b')) ← 𝒜 ck;
_ :: unit ← assert_spmf(m ≠ m' ∧ valid_msg m ∧ valid_msg m');
let b = verify (x1,y1) m c (a,b);
let b' = verify (x1,y1) m' c (a',b');
_ :: unit ← assert_spmf (b ∧ b');
return_spmf True}) True"
by(simp add: abstract_commitment.bind_game_alt_def split_def spmf_try_spmf del: verify.simps)
also have "... = spmf (do {
a' :: nat ← sample_uniform q;
b' :: nat ← sample_uniform q;
x1 :: nat ← sample_uniform q;
let y1 = (a' * x1 + b') mod q;
(c, m, (a,b), m', (a',b')) ← 𝒜 (a',b');
_ :: unit ← assert_spmf (m ≠ m' ∧ valid_msg m ∧ valid_msg m');
_ :: unit ← assert_spmf (c = (m + a) mod q ∧ y1 = (a * x1 + b) mod q ∧ c = (m' + a') mod q ∧ y1 = (a' * x1 + b') mod q);
return_spmf True}) True"
by(simp add: key_gen_def Let_def)
also have "... = spmf (do {
a'' :: nat ← sample_uniform q;
b'' :: nat ← sample_uniform q;
x1 :: nat ← sample_uniform q;
let y1 = (a'' * x1 + b'') mod q;
(c, m, (a,b), m', (a',b')) ← 𝒜 (a'',b'');
_ :: unit ← assert_spmf (m ≠ m' ∧ valid_msg m ∧ valid_msg m');
_ :: unit ← assert_spmf (c = (m + a) mod q ∧ y1 = (a * x1 + b) mod q ∧ c = (m' + a') mod q ∧ y1 = (a' * x1 + b') mod q);
return_spmf (?eq a a' b b' x1)}) True"
unfolding split_def Let_def
by(rule arg_cong2[where f=spmf, OF _ refl] bind_spmf_cong[OF refl])+
(auto simp add: eq_commute samp_uni_break' Let_def split_def valid_msg_def cong: bind_spmf_cong_simp)
also have "... ≤ spmf (do {
a'' :: nat ← sample_uniform q;
b'' :: nat ← sample_uniform q;
(c, m, (a,(b::nat)), m', (a',b')) ← 𝒜 (a'',b'');
map_spmf (?eq a a' b b') (sample_uniform q)}) True"
including monad_normalisation
unfolding split_def Let_def assert_spmf_def
apply(simp add: map_spmf_conv_bind_spmf)
apply(rule ord_spmf_eq_leD ord_spmf_bind_reflI)+
apply auto
done
also have "... ≤ 1/q"
proof((rule spmf_bind_leI)+, clarify)
fix a a' b b'
define A where "A = Collect (?eq a a' b b')"
define x1 where "x1 = The (?eq a a' b b')"
note q_gt_0[simp del]
have "A ⊆ {x1}" by(auto simp add: A_def x1_def)
hence "card (A ∩ {..<q}) ≤ card {x1}" by(intro card_mono) auto
also have "… = 1" by simp
finally have "spmf (map_spmf (λx. x ∈ A) (sample_uniform q)) True ≤ 1 / q"
using q_gt_0 unfolding sample_uniform_def
by(subst map_mem_spmf_of_set)(auto simp add: field_simps)
then show "spmf (map_spmf (?eq a a' b b') (sample_uniform q)) True ≤ 1 / q"
unfolding A_def mem_Collect_eq .
qed auto
finally show ?thesis .
qed
lemma rivest_bind:
shows "rivest_commit.bind_advantage 𝒜 ≤ 1 / q"
using bind_game_le_inv_q rivest_commit.bind_advantage_def by simp
end
locale rivest_asymp =
fixes q :: "nat ⇒ nat"
assumes rivest: "⋀η. rivest (q η)"
begin
sublocale rivest "q η" for η by(simp add: rivest)
theorem rivest_correct:
shows "rivest_commit.correct n"
using abstract_correct by simp
theorem rivest_perfect_hiding_asym:
assumes lossless_𝒜: "rivest_commit.lossless (𝒜 n)"
shows "rivest_commit.perfect_hiding_ind_cpa n (𝒜 n)"
by (simp add: lossless_𝒜 rivest_perfect_hiding)
theorem rivest_binding_asym:
assumes "negligible (λn. 1 / (q n))"
shows "negligible (λn. rivest_commit.bind_advantage n (𝒜 n))"
using negligible_le rivest_bind assms rivest_commit.bind_advantage_def by auto
end
end