import numpy as np
import math
from Crypto.Util.number import getPrime, inverse, bytes_to_long, long_to_bytes
import random
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a%b)
Components:
Conditions
• Given $K^{Pub}$, an attacker cannot feasibly determine $K^{Pri}$, nor can she determine any other private key that produces the same signatures as $K^{Pri}$.
• Given $K^{Pub}$ and a list of signed documents $D_1, . . . , D_n$ with their signatures $D^{sig}_1 , . . . , D_n^{sig}$, an attacker cannot feasibly determine a valid signature on any document $D$ that is not in the list $D_1, . . . , D_n$.
Key creation:
Signing:
Verification:
Proof:
$S^e≡D^{de}≡D(modN)$
def rsa_ds_key_creation():
p = getPrime(128)
q = getPrime(128)
N = p * q
while True:
e = random.randint(N//4,N-1)
if(gcd(e, (p-1)*(q-1)) == 1):
break
return (p, q), (N, e)
def rsa_ds_sign(p, q, D):
d = inverse(e, (p-1)*(q-1))
S = pow(D, d, N)
return S
def rsa_ds_verif(S, e, D):
return pow(S, e, N) == D
D = 1000
(p, q), (N, e) = rsa_ds_key_creation()
S = rsa_ds_sign(p, q, D)
rsa_ds_verif(S, e, D)
True
Public parameter creation:
Key creation:
Signing
$S_1≡g^k(mod \ p)$
$S2≡(D-aS_1)k^{-1} (mod \ p−1)$.
Verification
Proof:
$A^{S_1}·S_1^{S_2} ≡ g^{aS_1}·g^{kS_2} ≡ g^{aS_1+kS_2} ≡ g^{aS_1+k(D-aS_1)k^{-1}} ≡ g^{aS_1+(D-aS_1)} ≡ g^D \ (mod \ p)$
def elgamal_ds_key_creation():
p = getPrime(128)
g = 2 # or any other primitive root
a = random.randint(2, p)
A = pow(g, a, p)
return a, (p, g, A)
def elgamal_ds_sign(D, a, g, p):
while True:
k = random.randint(2, p)
if(gcd(k, p-1) == 1):
break
S_1 = pow(g, k, p)
S_2 = (D - a * S_1) * inverse(k, p-1) % (p-1)
return S_1, S_2
def elgamal_ds_verif(S_1, S_2, A, g, p, D):
return pow(A, S_1, p) * pow(S_1, S_2, p) % p == pow(g, D, p)
D = 1000
a, (p, g, A) = elgamal_ds_key_creation()
S_1, S_2 = elgamal_ds_sign(D, a, g, p)
elgamal_ds_verif(S_1, S_2, A, g, p, D)
True
Significantly shortens the signature by working in a subgroup of $\mathbb{F}^*_p$ of prime order $q$. The underlying assumption is that using the index calculus to solve the discrete logarithm problem in the subgroup is no easier than solving it in $\mathbb{F}^*_p$.
Public parameter creation:
Key creation
& Publish the verification key $A$
Signing
& Choose random element $1<k<q$
$S_1≡(g^k \ mod \ p) mod \ q$
$S_2≡(D+aS_1)k^{−1}(mod \ q)$
Verification
$V_1≡DS_2^{-1} (mod \ q)$
$V_2≡S_1S_2^{-1}(mod \ q)$
def DSA_key_creation(p, q, g):
a = 242
a = random.randint(2, q-1)
A = pow(g, a, p)
return a, A
def DSA_sign(D, a, g, p, q):
k = 427
k = random.randint(2, q)
S_1 = pow(g, k, p) % q
S_2 = ((D + a * S_1) * inverse(k, q)) % q
return S_1, S_2
def DSA_verif(S_1, S_2, A, g, p, q, D):
V_1 = (D*inverse(S_2, q)) % q
V_2 = (S_1 * inverse(S_2, q)) % q
return pow(g, V_1, p) * pow(A, V_2, p) % p % q == S_1
p = 48731
q = 443
g = 5260 # or any other primitive root
D = 343
a, A = DSA_key_creation(p, q, g)
A
4541
S_1, S_2 = DSA_sign(D, a, g, p, q)
S_1, S_2
(226, 76)
DSA_verif(S_1, S_2, A, g, p, q, D)
True