W-OTS uses relatively small key and signatures sizes, and is thought to be quantum robust. It generates 32x256 bit random private keys. We then hash these a number of times, and is defined by a parameter (w). If we use w=8, we hash the private keys by (\(2^{w}\)). This creates 32x256 bits public keys. The signature is the created by taking eight bits at a time, and then the 8-bit binary int (n) is subtracted from 256 and the private key is the hashed 256-n times. The signature is then 32 hashes which are derived from random private keys. To verify the signature, the recipient parses the hash of the signature (using 8 bits at a time, and extracting the 8 bit int, n). The signature is then derived from the signature.
Quantum Robust: Winternitz one time signature scheme (W-OTS)MethodThe method is:
This is illustrated below: PresentationCodeAn outline of the code for the key generation is (based on code [here]): # https://asecuritysite.com/encryption/wint import hashlib from binascii import unhexlify, hexlify from os import urandom import sys message="Hello" def random_key(n=32): #returns a 256 bit hex encoded (64 bytes) random number return hexlify(urandom(n)) def sha256(message): return hashlib.sha256(message.encode()).hexdigest() def sha256b(message): return hashlib.sha256(message.encode()).digest() def random_wkey(w=8, verbose=0): #create random W-OTS keypair priv = [] pub = [] print("Hashing number random keys by:\t",2**w) for x in range(256//w): a = str(random_key()) priv.append(a) for y in range(2**w-1): a = sha256(a) pub.append(sha256(a)) return priv, pub def sign_wkey(priv, message): signature = [] bin_msg = unhexlify(sha256(message)) for y in range(len(priv)): s = priv[y] for x in range(256-ord(bin_msg[y:y+1])): s = sha256(s) signature.append(s) return signature def verify_wkey(signature, message, pub): verify = [] bin_msg = unhexlify(sha256(message)) for x in range(len(signature)): a = signature[x] #f is all but last hash.. for z in range(ord(bin_msg[x:x+1])): a=sha256(a) #a = sha256(a) #g is the final hash, separate so can be changed.. verify.append(a) if pub != verify: return False return True priv, pub = random_wkey() print("==== Private key (keep secret) =====") print("Priv[0]: ",priv[0]) print("Priv[1]: ",priv[1]) print("Priv[2]: ",priv[2]) print("Priv[3]: ",priv[3]) print("Priv[4]: ",priv[4]) print("Priv[5]: ",priv[5]) print("==== Public key (show everyone)=====") print("Pub[0]: ",pub[0]) print("Pub[1]: ",pub[1]) print("Pub[2]: ",pub[2]) print("Pub[3]: ",pub[3]) print("Pub[4]: ",pub[4]) print("Pub[5]: ",pub[5]) print("==== Message to sign ===============") print("Message:\t",message) print("SHA-256:\t",sha256(message)) print("==== Signature =====================") sign = sign_wkey(priv,message) print("Sign[0]:\t",sign[0]) print("Sign[1]:\t",sign[1]) print("Sign[2]:\t",sign[2]) print("Sign[3]:\t",sign[3]) print("The signature test is ",verify_wkey(sign,message,pub)) A sample run which just shows the first few private key and the first public keys: Hashing number: 256 ==== Private key (keep secret) ===== Priv[0]: bd344c6110628aa38c9b5ca6458bed7b78425b2e82efa0624a578031562f82ee Priv[1]: 20670af5b1663fa9fad49fab6a692ae5989cff77439f98d2288f173b17a8d99f Priv[2]: 625aa290fd1f88c930451ff743d5d9ef90e7064368fb23a18c9fd048474818f2 Priv[3]: ee0e1363cbd5f61017ba27bfe91ec53969d28d143ed59a99efb020941bc4990f Priv[4]: ce94d7282ee3f7b05b99768695ff224b5994900c6182dfb89d596d8b7b405ec6 Priv[5]: d0c59651e951b0bb8d5a2d7b93f6739c9ce4a0c0c0f63bfce23b331b947eb285 ==== Public key (show everyone)===== Pub[0]: 45fdac6339e80cadd1331cce026cd0364ea84146a36f6f3f2449b66fb55a217a Pub[1]: 184cf92f22072fef078fa4a93ec2044f07ac8b12e326509474209312cace8a5a Pub[2]: a47548d4537bd284e7d7f935f41570866d9c6a72c463bb2a2b10c8c7907621f0 Pub[3]: 60395e575522cacb70d866211c64e8a74e562c79d1fffce224d1013d088bf66f Pub[4]: 8be7b53d5b56e698b8798f2a707fba7b8e417554fd489d74cc40fe8574d7589e Pub[5]: 9fac35971dae3a5c77ae7b5c720a72f90ee53852668c96c78e095cbb52af20a1 ==== Message to sign =============== Message: The quick brown fox jumps over the lazy dog SHA-256: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 ==== Signature ===================== Sign[0]: 45cb53c5c33af9b20426fd0233fd63d92bf0c2ded367163e6f2f93588a33c6d8 Sign[1]: e8c35987101f2d11d7056a2fe78069d3ed73aee315ebef8c2d40e04973301c26 Sign[2]: 59220d80b7c958957b28511f4081341cc4a00a0d6d5e1d05351be7dec3ca8aaa Sign[3]: 72a906d719be18e1592314bf6f6c521a325a9de2b5b9e9e13117bf01b0157f5c The signature test is True |