'''
High level classes and routines around public key encryption and decryption
'''
# import libnacl libs
import libnacl
import libnacl.encode


class BaseKey(object):
    '''
    Include methods for key management convenience
    '''
    def hex_sk(self):
        if hasattr(self, 'sk'):
            return libnacl.encode.hex_encode(self.sk)
        else:
            return ''

    def hex_pk(self):
        return libnacl.encode.hex_encode(self.pk)


class PublicKey(BaseKey):
    '''
    This class is used to manage public keys
    '''
    def __init__(self, pk):
        self.pk = pk


class SecretKey(BaseKey):
    '''
    This class is used to manage keypairs
    '''
    def __init__(self, sk=None):
        '''
        If a secret key is not passed in then it will be generated
        '''
        if sk is None:
            self.sk, self.pk = libnacl.crypto_box_keypair()
        elif len(sk) == libnacl.crypto_box_SECRETKEYBYTES:
            self.sk = sk
            self.pk = libnacl.crypto_scalarmult_base(sk)
        else:
            raise ValueError('Passed in invalid secret key')


class Box(object):
    '''
    TheBox class is used to create cryptographic boxes and unpack
    cryptographic boxes
    '''
    def __init__(self, sk, pk):
        if isinstance(sk, SecretKey):
            sk = sk.sk
        if isinstance(pk, SecretKey):
            raise ValueError('Passed in secret key as public key')
        if isinstance(pk, PublicKey):
            pk = pk.pk
        if pk and sk:
            self._k = libnacl.crypto_box_beforenm(sk, pk)

    def encrypt(self, msg, nonce=None):
        '''
        Encrypt the given message with the given nonce, if the nonce is not
        provided it will be generated from the libnacl.utils.time_nonce
        function
        '''
        if nonce is None:
            nonce = libnacl.utils.time_nonce()
        elif len(nonce) != libnacl.crypto_box_NONCEBYTES:
            raise ValueError('Invalid nonce size')
        ctxt = libnacl.crypto_box_afternm(self._k, msg, nonce)
        return nonce + ctxt

    def decrypt(self, ctxt, nonce=None):
        '''
        Decrypt the given message, if a nonce is passed in attempt to decrypt
        it with the given nonce, otherwise assum that the nonce is attached
        to the message
        '''
        if nonce is None:
            nonce = ctxt[:libnacl.crypto_box_NONCEBYTES]
            ctxt = ctxt[libnacl.crypto_box_NONCEBYTES:]
        elif len(nonce) != libnacl.crypto_box_NONCEBYTES:
            raise ValueError('Invalid nonce')
        msg = libnacl.crypto_box_open_afternm(self._k, ctxt, nonce)
        return msg

@@ -114,16 +114,37 @@
 libnacl%0A
+import libnacl.utils%0A
 import l
@@ -2033,25 +2033,16 @@
 afternm(
-self._k, 
 msg, non
@@ -2039,24 +2039,33 @@
 m(msg, nonce
+, self._k
 )%0A        re
@@ -2618,17 +2618,8 @@
 rnm(
-self._k, 
 ctxt
@@ -2625,16 +2625,25 @@
 t, nonce
+, self._k
 )%0A      

Correct calls to nm routines