-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFp.lean
More file actions
158 lines (114 loc) · 3.33 KB
/
Fp.lean
File metadata and controls
158 lines (114 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import Crypto.Field
import Mathlib.Control.Random
namespace Crypto.Field
private def gcdExtended (a : Nat) (b : Nat) : Int × Int × Int :=
if a = 0
then ⟨ b , 0 , 1 ⟩
else let ⟨ gcd , x' , y' ⟩ := gcdExtended (b % a) a
let x := y' - (b / a) * x'
let y := x'
⟨ gcd , x , y ⟩
termination_by a
decreasing_by
simp_wf
apply Nat.mod_lt
apply Nat.zero_lt_of_ne_zero
simp
assumption
private def modExp (m : Nat) (x : Nat) (n : Nat) : Nat :=
if n = 0
then 1
else let y := modExp m (x * x % m) (n / 2)
if n % 2 = 1
then x * y % m
else y
-- FIXME: Consider using `{p : Nat // p > 0}` instead of `Nat`.
structure Fp (p : Nat) where
private mkUnsafe ::
val : Nat
deriving Repr, DecidableEq, BEq
namespace Fp
def mk (x : Nat) : Fp p :=
⟨ x % p ⟩
def canonical (x : Fp p) : Prop :=
x.val < p
def invertible (x : Fp p) : Prop :=
let ⟨ gcd , _ , _ ⟩ := gcdExtended x.val p
gcd = 1
def inverse (x : Fp p) : Option (Fp p) :=
let ⟨ gcd , xi , _ ⟩ := gcdExtended x.val p
if gcd = 1
then some ⟨ (xi % p).toNat ⟩
else none
def xor : Fp p → Fp p → Fp p
| ⟨ x ⟩ , ⟨ y ⟩ => ⟨ x.xor y ⟩
def castFp : Fp p → Fp p' :=
Fp.mk ∘ Fp.val
def randFp [RandomGen g] [Monad m] {p : Nat} : RandGT g m (Fp p) :=
Fp.mkUnsafe
<$> Random.randBound Nat 0 (p - 1)
(Nat.zero_le (p - 1))
end Fp
instance : Inhabited (Fp p) where
default := Fp.mk 0
instance : OfNat (Fp p) n where
ofNat := Fp.mk n
instance : Add (Fp p) where
add x y := ⟨ (x.val + y.val) % p ⟩
instance : Neg (Fp p) where
neg x := ⟨ p - x.val % p ⟩
instance : Sub (Fp p) where
sub x y := ⟨ (p + x.val - y.val) % p ⟩
instance : Mul (Fp p) where
mul x y := ⟨ (x.val * y.val) % p ⟩
instance : Pow (Fp p) Nat where
pow x n := ⟨ modExp p x.val n ⟩
-- FIXME: Unsafe!
instance : Div (Fp p) where
div x y :=
match Fp.inverse y with
| some yi => x * yi
| none => 0
/-
instance : HDiv (Fp p) (Fp p) (Option (Fp p)) where
hDiv x y := Functor.map (Mul.mul x) $ Fp.inverse y
-/
instance [Monad m] {p : Nat} : Random m (Fp p) where
random := Fp.randFp
-- FIXME: Remove this or develop it further.
structure NonZeroFp (p : Nat) where
private mkUnsafe ::
val : Nat
nonzero : ¬ val % p = 0
namespace NonZeroFp
def mk (x : Fp p) (h : ¬ x.val % p = 0) : NonZeroFp p :=
NonZeroFp.mkUnsafe x.val h
def fp (x : NonZeroFp p) : Fp p :=
⟨ x.val ⟩
/-
private theorem invertible (x : NonZeroFp p) : (gcdExtended x.val p).fst = 1 := by
rw [gcdExtended]
simp
sorry
-/
-- FIXME: Strengthen this to yield `NonZeroFp p` instead of `Fp p`.
def inverse (x : NonZeroFp p) : Fp p :=
let ⟨ _ , xi , _⟩ := gcdExtended x.val p
⟨ (xi % p).toNat ⟩
end NonZeroFp
instance : HDiv (Fp p) (NonZeroFp p) (Fp p) where
hDiv x y := x * y.inverse
namespace Fp
def isSquare (x : Fp p) : Prop :=
match x^((p - 1) / 2) with
| Fp.mkUnsafe 0 => True
| Fp.mkUnsafe 1 => True
| _ => False
def Is3Mod4 (p : Nat) : Prop := p % 4 = 3
-- FIXME: Add a comprehensive set of instances.
instance instSqrt3Mod4 {p : Nat} (_ : Fp.Is3Mod4 p) : Sqrt (Fp p) where
sqrt (x : Fp p) :=
let c1 : Nat := (p + 1) / 4
x^c1
end Fp
end Crypto.Field