Library Stdlib.Zmod.ZstarBase
From
Stdlib
Require
Import
ZArith
ZModOffset
Zcong
Lia
Zdivisibility
.
From
Stdlib
Require
Import
Bool.Bool
Lists.List
Lists.Finite
Sorting.Permutation
.
Import
ListNotations
.
From
Stdlib
Require
Import
Zmod.ZmodDef
Zmod.ZmodBase
Zmod.ZstarDef
.
Local Open
Scope
Z_scope
.
Local Coercion
ZmodDef.Zmod.to_Z
:
Zmod
>->
Z
.
Local Coercion
Zstar.to_Zmod
:
Zstar.Zstar
>->
Zmod.Zmod
.
Local Hint Extern
0 (?
x
<->
?
x
) =>
reflexivity
:
core
.
Module
Zstar
.
Import
ZmodDef.Zmod
ZmodBase.Zmod
ZstarDef.Zstar
.
Conversions to
Zmod
Lemma
coprime_to_Zmod
[
m
] (
a
:
Zstar
m
) :
Z.coprime
(
to_Zmod
a
)
m
.
Notation
to_Zmod_range
:=
coprime_to_Zmod
(
only
parsing
).
Lemma
to_Zmod_inj
[
m
] (
x
y
:
Zstar
m
) :
to_Zmod
x
=
to_Zmod
y
->
x
=
y
.
Lemma
to_Zmod_inj_iff
[
m
] (
x
y
:
Zstar
m
) :
to_Zmod
x
=
to_Zmod
y
<->
x
=
y
.
Lemma
to_Zmod_of_coprime_Zmod
[
m
] (
x
:
Zmod
m
)
pf
:
to_Zmod
(
of_coprime_Zmod_dep
x
pf
)
=
x
.
Lemma
to_Zmod_of_Zmod'
[
m
] (
x
:
Zmod
m
) :
to_Zmod
(
of_Zmod
x
)
=
if
Z.eqb
(
Z.gcd
x
m
) 1
then
x
else
Zmod.one
.
Lemma
to_Zmod_of_Zmod
[
m
] (
x
:
Zmod
m
) (
H
:
Z.coprime
x
m
) :
to_Zmod
(
of_Zmod
x
)
=
x
.
Lemma
of_Zmod_to_Zmod
[
m
]
x
: @
of_Zmod
m
(
to_Zmod
x
)
=
x
.
Lemma
to_Zmod_1
m
: @
to_Zmod
m
one
=
Zmod.one
.
Lemma
of_Zmod_inj
[
m
] (
x
y
:
Zmod
m
) :
Z.coprime
x
m
->
Z.coprime
y
m
->
of_Zmod
x
=
of_Zmod
y
->
x
=
y
.
Lemma
to_Zmod_0_iff
[
m
] (
a
:
Zstar
m
) :
to_Zmod
a
=
zero
<->
Z.abs
m
=
1.
Lemma
to_Zmod_nz
[
m
] (
a
:
Zstar
m
) (
Hm
: 2
<=
m
) :
to_Zmod
a
<>
zero
.
Lemma
eqb_spec
[
m
] (
x
y
:
Zstar
m
) :
BoolSpec
(
x
=
y
) (
x
<>
y
) (
eqb
x
y
).
Lemma
eqb_eq
[
m
] (
x
y
:
Zstar
m
) :
eqb
x
y
=
true
<->
x
=
y
.
Lemma
eqb_refl
[
m
] (
x
:
Zstar
m
) :
eqb
x
x
=
true
.
Lemma
hprop_Zstar_1
(
a
b
:
Zstar
1) :
a
=
b
.
Lemma
hprop_Zstar_2
(
a
b
:
Zstar
2) :
a
=
b
.
Lemma
wlog_eq_Zstar_3_pos
[
m
] (
a
b
:
Zstar
m
) (
Hm
: 0
<
m
) (
k
: 3
<=
m
->
a
=
b
) :
a
=
b
.
Lemma
of_Zmod_1
m
: @
of_Zmod
m
Zmod.one
=
one
.
Lemma
to_Z_0_iff
[
m
] (
a
:
Zstar
m
) :
to_Z
a
=
0
<->
Z.abs
m
=
1.
Lemma
to_Z_nz_iff
[
m
] (
a
:
Zstar
m
) :
to_Z
a
<>
0
<->
Z.abs
m
<>
1.
Lemma
to_Z_nz
[
m
] (
a
:
Zstar
m
) :
Z.abs
m
<>
1
->
to_Z
a
<>
0.
opp
Lemma
to_Zmod_opp
[
m
] (
a
:
Zstar
m
) :
to_Zmod
(
opp
a
)
=
Zmod.opp
a
.
Lemma
opp_opp
[
m
] (
a
:
Zstar
m
) :
opp
(
opp
a
)
=
a
.
Lemma
opp_inj
[
m
] (
a
b
:
Zstar
m
) :
opp
a
=
opp
b
->
a
=
b
.
Lemma
opp_distinct_odd
[
m
] (
Hm
:
m
mod
2
=
1) (
Hm'
: 3
<=
m
)
a
:
a
<>
opp
a
:>
Zstar
m
.
Lemma
opp_1_neq_1
[
m
] (
Hm
: 3
<=
Z.abs
m
) :
opp
one
<>
one
:>
Zstar
m
.
abs
Lemma
to_Zmod_abs
[
m
] (
a
:
Zstar
m
) :
to_Zmod
(
abs
a
)
=
Zmod.abs
a
.
Lemma
abs_1
m
: @
abs
m
one
=
one
.
Lemma
abs_nonneg
[
m
] (
x
:
Zstar
m
) : 0
<=
@
signed
m
x
->
abs
x
=
x
.
Lemma
abs_neg
[
m
] (
x
:
Zstar
m
) : @
signed
m
x
<
0
->
abs
x
=
opp
x
.
Lemma
abs_pos
[
m
] (
x
:
Zstar
m
) : 0
<
@
signed
m
x
->
abs
x
=
x
.
Lemma
abs_opp
[
m
]
x
: @
abs
m
(
opp
x
)
=
abs
x
.
Lemma
abs_abs
[
m
] (
x
:
Zstar
m
) :
abs
(
abs
x
)
=
abs
x
.
Lemma
abs_overflow
[
m
] (
Hm
:
m
mod
2
=
0)
(
x
:
Zstar
m
) (
Hx
:
signed
x
=
-
m
/
2) :
abs
x
=
x
.
mul
Lemma
to_Zmod_mul
[
m
] (
a
b
:
Zstar
m
) : @
to_Zmod
m
(
mul
a
b
)
=
Zmod.mul
a
b
.
Lemma
of_Zmod_mul
[
m
] (
a
b
:
Zmod
m
) (
Ha
:
Z.coprime
a
m
) (
Hb
:
Z.coprime
b
m
) :
@
of_Zmod
m
(
Zmod.mul
a
b
)
=
mul
(
of_Zmod
a
) (
of_Zmod
b
).
Lemma
mul_assoc
[
m
]
a
b
c
: @
mul
m
a
(
mul
b
c
)
=
mul
(
mul
a
b
)
c
.
Lemma
mul_comm
[
m
]
a
b
: @
mul
m
a
b
=
mul
b
a
.
Lemma
mul_1_l
[
m
]
a
: @
mul
m
one
a
=
a
.
Lemma
mul_1_r
[
m
]
a
: @
mul
m
a
one
=
a
.
Lemma
mul_m1_l
[
m
]
a
: @
mul
m
(
opp
one
)
a
=
opp
a
.
Lemma
mul_m1_r
[
m
]
a
: @
mul
m
a
(
opp
one
)
=
opp
a
.
Lemma
mul_opp_l
[
m
] (
a
b
:
Zstar
m
) :
mul
(
opp
a
)
b
=
opp
(
mul
a
b
).
Lemma
mul_opp_r
[
m
] (
a
b
:
Zstar
m
) :
mul
a
(
opp
b
)
=
opp
(
mul
a
b
).
Lemma
mul_opp_opp
[
m
]
a
b
: @
mul
m
(
opp
a
) (
opp
b
)
=
mul
a
b
.
Lemma
abs_mul_abs_l
[
m
] (
x
y
:
Zstar
m
) :
abs
(
mul
(
abs
x
)
y
)
=
abs
(
mul
x
y
).
Lemma
abs_mul_abs_r
[
m
] (
x
y
:
Zstar
m
) :
abs
(
mul
x
(
abs
y
))
=
abs
(
mul
x
y
).
Lemma
abs_mul_abs_abs
[
m
] (
x
y
:
Zstar
m
) :
abs
(
mul
(
abs
x
) (
abs
y
))
=
abs
(
mul
x
y
).
inv
and
div
Lemma
to_Zmod_inv
[
m
]
x
:
to_Zmod
(@
inv
m
x
)
=
Zmod.inv
x
.
Lemma
not_of_Zmod_inv
(
m
:= 6) (
x
:=
Zmod.of_Z
_
4) :
of_Zmod
(@
Zmod.inv
m
x
)
<>
inv
(
of_Zmod
x
).
Lemma
to_Zmod_div
[
m
]
x
y
:
to_Zmod
(@
div
m
x
y
)
=
Zmod.mdiv
x
y
.
Lemma
mul_inv_l
[
m
]
x
y
:
mul
(@
inv
m
y
)
x
=
div
x
y
.
Lemma
mul_inv_r
[
m
]
x
y
:
mul
x
(@
inv
m
y
)
=
div
x
y
.
Lemma
div_same
[
m
] (
a
:
Zstar
m
) :
div
a
a
=
one
.
Lemma
div_mul_l
[
m
] (
a
b
c
:
Zstar
m
) :
div
(
mul
a
b
)
c
=
mul
a
(
div
b
c
).
Lemma
mul_inv_same_l
[
m
]
x
:
mul
(@
inv
m
x
)
x
=
one
.
Lemma
mul_inv_same_r
[
m
]
x
:
mul
x
(@
inv
m
x
)
=
one
.
Lemma
inv_inv
[
m
]
x
:
inv
(@
inv
m
x
)
=
x
.
Lemma
inv_1
m
: @
inv
m
one
=
one
.
Lemma
div_1_r
[
m
]
x
: @
div
m
x
one
=
x
.
Lemma
mul_cancel_l
[
m
] (
a
b
c
:
Zstar
m
) (
H
:
mul
a
b
=
mul
a
c
) :
b
=
c
.
Lemma
mul_cancel_l_iff
[
m
] (
a
b
c
:
Zstar
m
) :
mul
a
b
=
mul
a
c
<->
b
=
c
.
Lemma
mul_cancel_r
[
m
] (
a
b
c
:
Zstar
m
) (
H
:
mul
b
a
=
mul
c
a
) :
b
=
c
.
Lemma
mul_cancel_r_iff
[
m
] (
a
b
c
:
Zstar
m
) :
mul
b
a
=
mul
c
a
<->
b
=
c
.
Lemma
mul_div_r_same_r
[
m
] (
a
b
:
Zstar
m
) :
mul
a
(
div
b
a
)
=
b
.
Lemma
inv_mul
[
m
] (
a
b
:
Zstar
m
) :
inv
(
mul
a
b
)
=
mul
(
inv
a
) (
inv
b
).
Lemma
div_div_r_same
[
m
] (
a
b
:
Zstar
m
) :
div
a
(
div
a
b
)
=
b
.
Lemma
inv_div
[
m
] (
x
y
:
Zstar
m
) :
inv
(
div
x
y
)
=
div
y
x
.
Lemma
eq_inv_iff
[
m
] (
x
y
:
Zstar
m
) :
inv
x
=
y
<->
mul
x
y
=
one
.
Lemma
inv_opp
[
m
] (
x
:
Zstar
m
) :
inv
(
opp
x
)
=
opp
(
inv
x
).
prod
Lemma
prod_nil
m
:
prod
[]
=
@
one
m
.
Lemma
prod_cons
[
m
] (
x
:
Zstar
m
)
xs
:
prod
(
x
::
xs
)
=
mul
x
(
prod
xs
).
Lemma
prod_singleton
[
m
] (
x
:
Zstar
m
) :
prod
[
x
]
=
x
.
Lemma
prod_Permutation
[
m
] (
xs
ys
:
list
(
Zstar
m
)) (
H
:
Permutation
xs
ys
) :
prod
xs
=
prod
ys
.
Lemma
prod_app
[
m
]
xs
ys
:
prod
(
xs
++
ys
)
=
mul
(
prod
xs
) (
prod
ys
)
:>
Zstar
m
.
Lemma
prod_flat_map
[
A
] [
m
] (
f
:
A
->
_
) (
xs
:
list
A
) :
prod
(
flat_map
f
xs
)
=
prod
(
map
(
fun
x
=>
prod
(
f
x
))
xs
)
:>
Zstar
m
.
Lemma
prod_concat
[
m
] (
xss
:
list
(
list
(
Zstar
m
))) :
prod
(
concat
xss
)
=
prod
((
map
(
fun
xs
=>
prod
xs
))
xss
)
:>
Zstar
m
.
Lemma
prod_rev
[
m
] (
xs
:
list
(
Zstar
m
)) :
prod
(
rev
xs
)
=
prod
xs
.
pow
Lemma
to_Zmod_pow
[
m
] (
a
:
Zstar
m
)
z
: @
to_Zmod
m
(
pow
a
z
)
=
Zmod.pow
a
z
.
Lemma
pow_0_r
[
m
]
x
: @
pow
m
x
0
=
one
.
Lemma
pow_1_r
[
m
]
x
: @
pow
m
x
1
=
x
.
Lemma
pow_2_r
[
m
]
x
: @
pow
m
x
2
=
mul
x
x
.
Lemma
pow_opp_2
[
m
] (
x
:
Zstar
m
) :
pow
(
opp
x
) 2
=
pow
x
2.
Lemma
pow_abs_2
[
m
] (
x
:
Zstar
m
) :
pow
(
abs
x
) 2
=
pow
x
2.
Lemma
eq_abs_iff
m
(
x
y
:
Zstar
m
) :
abs
x
=
abs
y
<->
(
y
=
x
\/
y
=
opp
x
)
.
Lemma
Private_coprime_Zmodpow
[
m
] (
a
:
Zstar
m
)
z
(
H
: 0
<=
z
) :
Z.coprime
(
Zmod.pow
a
z
)
m
.
Lemma
pow_opp_r
[
m
]
a
(
z
:
Z
) : @
pow
m
a
(
-
z
)
=
inv
(
pow
a
z
).
Local Lemma
Private_pow_succ_r_nonneg
[
m
] (
x
:
Zstar
m
)
z
(
H
: 0
<=
z
) :
pow
x
(
Z.succ
z
)
=
mul
x
(
pow
x
z
).
Lemma
pow_succ_r
[
m
] (
x
:
Zstar
m
)
z
:
pow
x
(
Z.succ
z
)
=
mul
x
(
pow
x
z
).
Lemma
pow_pred_r
[
m
] (
x
:
Zstar
m
)
z
:
pow
x
(
Z.pred
z
)
=
div
(
pow
x
z
)
x
.
Lemma
pow_1_l
[
m
]
z
: @
pow
m
one
z
=
one
.
Lemma
pow_add_r
[
m
] (
x
:
Zstar
m
)
a
b
:
pow
x
(
a
+
b
)
=
mul
(
pow
x
a
) (
pow
x
b
).
Lemma
pow_sub_r
[
m
] (
x
:
Zstar
m
)
a
b
:
pow
x
(
a
-
b
)
=
div
(
pow
x
a
) (
pow
x
b
).
Lemma
pow_mul_r
[
m
] (
x
:
Zstar
m
)
a
b
:
pow
x
(
a
*
b
)
=
pow
(
pow
x
a
)
b
.
Lemma
pow_mul_l
[
m
] (
x
y
:
Zstar
m
)
n
:
pow
(
mul
x
y
)
n
=
mul
(
pow
x
n
) (
pow
y
n
).
Lemma
inv_pow_m1
m
n
: @
inv
m
(
pow
(
opp
one
)
n
)
=
pow
(
opp
one
)
n
.
Lemma
prod_repeat
[
m
] (
a
:
Zstar
m
)
n
:
prod
(
repeat
a
n
)
=
pow
a
(
Z.of_nat
n
).
Lemma
prod_map_mul
[
m
] (
a
:
Zstar
m
)
xs
:
prod
(
List.map
(
mul
a
)
xs
)
=
mul
(
pow
a
(
Z.of_nat
(
length
xs
))) (
prod
xs
).
Lemma
prod_pow
[
m
]
z
xs
:
prod
(
map
(
fun
x
=>
pow
x
z
)
xs
)
=
pow
(
prod
xs
)
z
:>
Zstar
m
.
Lemma
prod_opp
[
m
]
xs
:
prod
(
map
(@
opp
m
)
xs
)
=
mul
(
pow
(
opp
one
) (
Z.of_nat
(
length
xs
))) (
prod
xs
).
elements
Lemma
in_of_Zmod_filter
[
m
]
x
(
l
:
list
(
Zmod
m
)) :
In
x
(
map
of_Zmod
(
filter
(
fun
y
:
Zmod
m
=>
Z.gcd
y
m
=?
1)
l
))
<->
In
(
to_Zmod
x
)
l
.
Lemma
in_elements
[
m
] (
x
:
Zstar
m
) :
In
x
(
elements
m
).
Lemma
NoDup_elements
m
:
NoDup
(
elements
m
).
Lemma
to_Zmod_elements
m
:
List.map
to_Zmod
(
elements
m
)
=
Zmod.invertibles
m
.
Lemma
elements_by_sign
[
m
] (
Hm
: 2
<=
Z.abs
m
) :
elements
m
=
positives
m
++
negatives
m
.
Lemma
in_positives
[
m
] (
x
:
Zstar
m
) (
Hm
:
m
<>
0) :
In
x
(
positives
m
)
<->
0
<
signed
x
.
Lemma
in_negatives
[
m
] (
x
:
Zstar
m
) (
Hm
:
m
<>
0) :
In
x
(
negatives
m
)
<->
signed
x
<
0.
Lemma
negatives_as_positives_odd
m
(
Hm
:
m
mod
2
=
1) :
negatives
m
=
map
opp
(
rev
(
positives
m
)).
Lemma
NoDup_positives
m
:
NoDup
(
positives
m
).
Lemma
NoDup_negatives
m
:
NoDup
(
negatives
m
).
Local Hint Unfold
Injective
List.incl
:
core
.
Lemma
Permutation_mul_elements
[
m
] (
a
:
Zstar
m
) :
Permutation
(
List.map
(
mul
a
) (
elements
m
)) (
elements
m
).
Theorem
euler
[
m
] (
a
:
Zstar
m
) :
pow
a
(
Z.of_nat
(
length
(
elements
m
)))
=
one
.
Lemma
to_Zmod_elements_prime
p
(
H
:
Z.prime
p
) :
List.map
to_Zmod
(
elements
p
)
=
List.tl
(
Zmod.elements
p
).
Lemma
length_elements_prime
p
(
H
:
Z.prime
p
) :
length
(
elements
p
)
=
Z.to_nat
(
p
-
1).
Lemma
length_positives_length_negatives_odd
m
(
Hm
:
m
mod
2
=
1) :
length
(
positives
m
)
=
length
(
negatives
m
).
Lemma
length_positives_odd
[
m
] (
H
:
m
mod
2
=
1) :
length
(
positives
m
)
=
(
length
(
elements
m
)
/
2)%
nat
.
Lemma
length_negatives_odd
[
m
] (
H
:
m
mod
2
=
1) :
length
(
negatives
m
)
=
(
length
(
elements
m
)
/
2)%
nat
.
Local Lemma
Private_odd_prime
(
p
:
Z
) :
Z.prime
p
->
3
<=
p
->
p
mod
2
=
1.
Lemma
length_positives_prime
[
m
] (
H
:
Z.prime
m
) :
length
(
positives
m
)
=
Z.to_nat
(
(
m
-
1
)
/
2).
Lemma
length_negatives_prime
[
m
] (
H
:
Z.prime
m
) :
length
(
negatives
m
)
=
Z.to_nat
(
m
/
2).
Theorem
fermat
[
m
] (
a
:
Zstar
m
) (
H
:
Z.prime
m
) :
pow
a
(
Z.pred
m
)
=
one
.
Theorem
fermat_inv
[
m
] (
a
:
Zstar
m
) (
H
:
Z.prime
m
) :
pow
a
(
m
-
2)
=
inv
a
.
Theorem
euler_criterion_square
[
p
] (
Hp
:
Z.prime
p
)
(
a
sqrt_a
:
Zstar
p
) (
Ha
:
pow
sqrt_a
2
=
a
) :
pow
a
(
(
p
-
1
)/
2)
=
one
.
End
Zstar
.