{
var ainv:prime := 0;
var i:ℕ[K^2];
-
- if a = 1 then
- {
- ainv = 1;
- }
- else
+
+ // straight search
+ // algorithmic alternative: Euclidean algorithm
+ for i=1;i<p;i=i+1 do
+ decreases p-i;
+ if a*i % p = 1 then
+ ainv = i;
+
+ return ainv;
+}
+
+proc integerroot(a:nat): nat
+ ensures result^2 ≤ a ∧ a < (result+1)^2;
+{
+ var x:nat = 0;
+ var y:ℕ[(K+1)^2] = 1;
+ var z:ℕ[(K+1)^2] = 1;
+
+ while y ≤ a do
+ invariant x^2 ≤ a ∧ y = x^2+z ∧ z = 2*x+1;
{
- for i=1;i<p;i=i+1 do
- if a*i % p = 1 then
- ainv = i;
+ x=x+1;
+ z=z+2;
+ y=y+z;
}
- return ainv;
+
+ return x;
}
-proc discrete_log(p:prime,g:nat,a:nat,m:nat): res
+proc DiscreteLog(p:prime,g:nat,a:nat): res
requires 1 < p ∧ isPrime(p) ∧ // p is a prime greater than 1
1 < g ∧ g < p ∧
1 < a ∧ ¬divides(p,a) ∧
- 8 < m ∧
∀b:nat. (0 < b ∧ b < p-1) ⇒ (g^b % p ≠ 1) ∧ g^(p-1)%p = 1 ∧ // g has order p-1
0 ≤ a ∧ a < p; // a is in ℤ/pℤ
ensures (g^result)%p = a;
var A:Array[20,nat]; // Q: Is it possible to dynamically allocate??
var b:Array[20,nat]; // Q: Is it possible to dynamically allocate??
var gim:prime := g;
+ var m:nat := integerroot(p-1)+2; // actually \lceil sqrt(p-1) \rceil // TODO
A = Array[20,nat](0); // Q: Is it possible to dynamically allocate??
b = Array[20,nat](0); // Q: Is it possible to dynamically allocate??
var gi:prime = InvModP(g,p);
for var i:nat=1;i<m;i=i+1 do
+ decreases m-i;
{
- A[i] = A[i-1]*g%p;
+ A[i] = A[i-1]*g%p; // Baby-Step
gim = gim*gi % p;
}
for var i:nat=0;i<m;i=i+1 do
+ decreases m-i;
{
for var j:nat=0;j<m;j=j+1 do
+ decreases m-j;
{
if A[j] = b[i] then
{
// result found
ret = i*m + j;
// abort loop
- i = m-1;
+ // Q: Is there a more comfortable way (e.g. break??)
+ i = m-1;
j = m-1;
}
}
- b[i+1] = b[i]*gim % p;
+ b[i+1] = b[i]*gim % p; // Giant-Step
}
return ret;
proc main(): ()
{
- print discrete_log(11,2,10,10);
+ print DiscreteLog(11,2,10);
}
+