eddsa.py
1 # MIT License 2 # 3 # Copyright (c) 2015 Brian Warner and other contributors 4 5 # Permission is hereby granted, free of charge, to any person obtaining a copy 6 # of this software and associated documentation files (the "Software"), to deal 7 # in the Software without restriction, including without limitation the rights 8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 # copies of the Software, and to permit persons to whom the Software is 10 # furnished to do so, subject to the following conditions: 11 # 12 # The above copyright notice and this permission notice shall be included in all 13 # copies or substantial portions of the Software. 14 # 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 # SOFTWARE. 22 23 from RNS.Cryptography.Hashes import sha512 24 from .basic import (bytes_to_clamped_scalar, 25 bytes_to_scalar, scalar_to_bytes, 26 bytes_to_element, Base) 27 import hashlib, binascii 28 29 def H(m): 30 return sha512(m) 31 32 def publickey(seed): 33 # turn first half of SHA512(seed) into scalar, then into point 34 assert len(seed) == 32 35 a = bytes_to_clamped_scalar(H(seed)[:32]) 36 A = Base.scalarmult(a) 37 return A.to_bytes() 38 39 def Hint(m): 40 h = H(m) 41 return int(binascii.hexlify(h[::-1]), 16) 42 43 def signature(m,sk,pk): 44 assert len(sk) == 32 # seed 45 assert len(pk) == 32 46 h = H(sk[:32]) 47 a_bytes, inter = h[:32], h[32:] 48 a = bytes_to_clamped_scalar(a_bytes) 49 r = Hint(inter + m) 50 R = Base.scalarmult(r) 51 R_bytes = R.to_bytes() 52 S = r + Hint(R_bytes + pk + m) * a 53 return R_bytes + scalar_to_bytes(S) 54 55 def checkvalid(s, m, pk): 56 if len(s) != 64: raise Exception("signature length is wrong") 57 if len(pk) != 32: raise Exception("public-key length is wrong") 58 R = bytes_to_element(s[:32]) 59 A = bytes_to_element(pk) 60 S = bytes_to_scalar(s[32:]) 61 h = Hint(s[:32] + pk + m) 62 v1 = Base.scalarmult(S) 63 v2 = R.add(A.scalarmult(h)) 64 return v1==v2 65 66 # wrappers 67 68 import os 69 70 def create_signing_key(): 71 seed = os.urandom(32) 72 return seed 73 74 def create_verifying_key(signing_key): 75 return publickey(signing_key) 76 77 def sign(skbytes, msg): 78 """Return just the signature, given the message and just the secret 79 key.""" 80 if len(skbytes) != 32: 81 raise ValueError("Bad signing key length %d" % len(skbytes)) 82 vkbytes = create_verifying_key(skbytes) 83 sig = signature(msg, skbytes, vkbytes) 84 return sig 85 86 def verify(vkbytes, sig, msg): 87 if len(vkbytes) != 32: 88 raise ValueError("Bad verifying key length %d" % len(vkbytes)) 89 if len(sig) != 64: 90 raise ValueError("Bad signature length %d" % len(sig)) 91 rc = checkvalid(sig, msg, vkbytes) 92 if not rc: 93 raise ValueError("rc != 0", rc) 94 return True