updated IS codes
This commit is contained in:
parent
a5c9c120ff
commit
13bcfbbafd
7 changed files with 356 additions and 1 deletions
104
IS/Lab/Lab6/elgamal_schnorr.py
Normal file
104
IS/Lab/Lab6/elgamal_schnorr.py
Normal file
|
@ -0,0 +1,104 @@
|
|||
import os
|
||||
import random
|
||||
from typing import Tuple
|
||||
|
||||
from Crypto.Hash import SHA256
|
||||
from Crypto.Util.number import getPrime
|
||||
|
||||
|
||||
def elgamal_keygen(bits: int = 512) -> Tuple[Tuple[int, int, int], int]:
|
||||
p = getPrime(bits)
|
||||
g = random.randrange(2, p - 1)
|
||||
x = random.randrange(1, p - 1)
|
||||
h = pow(g, x, p)
|
||||
return (p, g, h), x
|
||||
|
||||
|
||||
def elgamal_encrypt(message: bytes, pub_key: Tuple[int, int, int]) -> Tuple[int, int]:
|
||||
p, g, h = pub_key
|
||||
m = int.from_bytes(message, "big")
|
||||
if m >= p:
|
||||
raise ValueError("Message too large for key size")
|
||||
k = random.randrange(1, p - 1)
|
||||
c1 = pow(g, k, p)
|
||||
s = pow(h, k, p)
|
||||
c2 = (m * s) % p
|
||||
return c1, c2
|
||||
|
||||
|
||||
def elgamal_decrypt(ciphertext: Tuple[int, int], priv_key: int, pub_key: Tuple[int, int, int]) -> bytes:
|
||||
c1, c2 = ciphertext
|
||||
p, _, _ = pub_key
|
||||
s = pow(c1, priv_key, p)
|
||||
s_inv = pow(s, p - 2, p)
|
||||
m = (c2 * s_inv) % p
|
||||
if m == 0:
|
||||
return b""
|
||||
m_len = (m.bit_length() + 7) // 8
|
||||
return m.to_bytes(m_len, "big")
|
||||
|
||||
|
||||
def schnorr_keygen(bits: int = 512) -> Tuple[Tuple[int, int, int], int]:
|
||||
# Use same style group as ElGamal demo for simplicity
|
||||
p = getPrime(bits)
|
||||
g = random.randrange(2, p - 1)
|
||||
x = random.randrange(1, p - 1)
|
||||
y = pow(g, x, p)
|
||||
return (p, g, y), x
|
||||
|
||||
|
||||
def schnorr_sign(message: bytes, priv_key: int, params: Tuple[int, int, int]) -> Tuple[int, int]:
|
||||
p, g, _ = params
|
||||
k = random.randrange(1, p - 1)
|
||||
r = pow(g, k, p)
|
||||
h = SHA256.new()
|
||||
h.update(r.to_bytes((r.bit_length() + 7) // 8 or 1, "big") + message)
|
||||
e = int.from_bytes(h.digest(), "big") % (p - 1)
|
||||
s = (k + e * priv_key) % (p - 1)
|
||||
return e, s
|
||||
|
||||
|
||||
def schnorr_verify(message: bytes, signature: Tuple[int, int], params: Tuple[int, int, int]) -> bool:
|
||||
p, g, y = params
|
||||
e, s = signature
|
||||
# Compute r' = g^s * y^{-e} mod p
|
||||
y_inv_e = pow(y, (p - 1 - e) % (p - 1), p)
|
||||
r_prime = (pow(g, s, p) * y_inv_e) % p
|
||||
h = SHA256.new()
|
||||
h.update(r_prime.to_bytes((r_prime.bit_length() + 7) // 8 or 1, "big") + message)
|
||||
e_prime = int.from_bytes(h.digest(), "big") % (p - 1)
|
||||
return e_prime == e
|
||||
|
||||
|
||||
def demo() -> None:
|
||||
print("Lab6: ElGamal (encrypt/decrypt) and Schnorr (sign/verify) demo")
|
||||
default_msg = os.environ.get("LAB6_MESSAGE", "Test message for Lab6")
|
||||
try:
|
||||
user_msg = input(f"Enter plaintext [{default_msg}]: ").strip()
|
||||
except EOFError:
|
||||
user_msg = ""
|
||||
message = (user_msg or default_msg).encode()
|
||||
|
||||
# ElGamal
|
||||
pub_e, priv_e = elgamal_keygen(512)
|
||||
c1, c2 = elgamal_encrypt(message, pub_e)
|
||||
recovered = elgamal_decrypt((c1, c2), priv_e, pub_e)
|
||||
print("\nElGamal:")
|
||||
print(f"- Public: p({pub_e[0].bit_length()} bits), g, h")
|
||||
print(f"- Ciphertext c1={hex(c1)[:18]}..., c2={hex(c2)[:18]}...")
|
||||
print(f"- Decrypt OK: {recovered == message}")
|
||||
|
||||
# Schnorr
|
||||
pub_s, priv_s = schnorr_keygen(512)
|
||||
sig = schnorr_sign(message, priv_s, pub_s)
|
||||
ok = schnorr_verify(message, sig, pub_s)
|
||||
print("\nSchnorr:")
|
||||
print(f"- Public: p({pub_s[0].bit_length()} bits), g, y")
|
||||
print(f"- Signature e={sig[0]}, s={sig[1]}")
|
||||
print(f"- Verify OK: {ok}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo()
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue