51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
|
import os
|
||
|
import warnings
|
||
|
from collections import namedtuple
|
||
|
|
||
|
from . import djbec
|
||
|
|
||
|
__all__ = ['crypto_sign', 'crypto_sign_open', 'crypto_sign_keypair', 'Keypair',
|
||
|
'PUBLICKEYBYTES', 'SECRETKEYBYTES', 'SIGNATUREBYTES']
|
||
|
|
||
|
PUBLICKEYBYTES = 32
|
||
|
SECRETKEYBYTES = 64
|
||
|
SIGNATUREBYTES = 64
|
||
|
|
||
|
Keypair = namedtuple('Keypair', ('vk', 'sk')) # verifying key, secret key
|
||
|
|
||
|
|
||
|
def crypto_sign_keypair(seed=None):
|
||
|
"""Return (verifying, secret) key from a given seed, or os.urandom(32)"""
|
||
|
if seed is None:
|
||
|
seed = os.urandom(PUBLICKEYBYTES)
|
||
|
else:
|
||
|
warnings.warn("ed25519ll should choose random seed.",
|
||
|
RuntimeWarning)
|
||
|
if len(seed) != 32:
|
||
|
raise ValueError("seed must be 32 random bytes or None.")
|
||
|
skbytes = seed
|
||
|
vkbytes = djbec.publickey(skbytes)
|
||
|
return Keypair(vkbytes, skbytes+vkbytes)
|
||
|
|
||
|
|
||
|
def crypto_sign(msg, sk):
|
||
|
"""Return signature+message given message and secret key.
|
||
|
The signature is the first SIGNATUREBYTES bytes of the return value.
|
||
|
A copy of msg is in the remainder."""
|
||
|
if len(sk) != SECRETKEYBYTES:
|
||
|
raise ValueError("Bad signing key length %d" % len(sk))
|
||
|
vkbytes = sk[PUBLICKEYBYTES:]
|
||
|
skbytes = sk[:PUBLICKEYBYTES]
|
||
|
sig = djbec.signature(msg, skbytes, vkbytes)
|
||
|
return sig + msg
|
||
|
|
||
|
|
||
|
def crypto_sign_open(signed, vk):
|
||
|
"""Return message given signature+message and the verifying key."""
|
||
|
if len(vk) != PUBLICKEYBYTES:
|
||
|
raise ValueError("Bad verifying key length %d" % len(vk))
|
||
|
rc = djbec.checkvalid(signed[:SIGNATUREBYTES], signed[SIGNATUREBYTES:], vk)
|
||
|
if not rc:
|
||
|
raise ValueError("rc != True", rc)
|
||
|
return signed[SIGNATUREBYTES:]
|