def test_scalarmult_ed25519_unavailable(): zero = 32 * b"\x00" with pytest.raises(UnavailableError): c.crypto_scalarmult_ed25519_base(zero) with pytest.raises(UnavailableError): c.crypto_scalarmult_ed25519_base_noclamp(zero) with pytest.raises(UnavailableError): c.crypto_scalarmult_ed25519(zero, zero) with pytest.raises(UnavailableError): c.crypto_scalarmult_ed25519_noclamp(zero, zero)
def test_scalarmult_ed25519_noclamp(): # An arbitrary scalar which is known to differ once clamped scalar = 32 * b'\x01' BASEPOINT = bytes(bytearray([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66] ) ) p = c.crypto_scalarmult_ed25519_noclamp(scalar, BASEPOINT) pb = c.crypto_scalarmult_ed25519_base_noclamp(scalar) pc = c.crypto_scalarmult_ed25519_base(scalar) assert p == pb assert pb != pc # clamp manually ba = bytearray(scalar) ba0 = bytes(bytearray([ba[0] & 248])) ba31 = bytes(bytearray([(ba[31] & 127) | 64])) scalar_clamped = ba0 + bytes(ba[1:31]) + ba31 p1 = c.crypto_scalarmult_ed25519_noclamp(scalar_clamped, BASEPOINT) p2 = c.crypto_scalarmult_ed25519(scalar, BASEPOINT) assert p1 == p2
def test_scalarmult_ed25519(): SCALARBYTES = c.crypto_scalarmult_ed25519_SCALARBYTES # the minimum ed25519 scalar is represented by a 8 value in the # first octet, a 64 value in the last octet, and all zeros # in between: MINSC = bytes(bytearray([8] + (SCALARBYTES - 2) * [0] + [64])) # the scalar multiplication formula for ed25519 # "clamps" the scalar by setting the most significant bit # of the last octet to zero, therefore scalar multiplication # by CLMPD is equivalent to scalar multiplication by MINSC CLMPD = bytes(bytearray([8] + (SCALARBYTES - 2) * [0] + [192])) MIN_P1 = bytes(bytearray([9] + (SCALARBYTES - 2) * [0] + [64])) MIN_P7 = bytes(bytearray([15] + (SCALARBYTES - 2) * [0] + [64])) MIN_P8 = bytes(bytearray([16] + (SCALARBYTES - 2) * [0] + [64])) p, _s = c.crypto_sign_keypair() _p = p for i in range(254): # double _p _p = c.crypto_core_ed25519_add(_p, _p) for i in range(8): _p = c.crypto_core_ed25519_add(_p, p) # at this point _p is (2^254+8) times p assert c.crypto_scalarmult_ed25519(MINSC, p) == _p assert c.crypto_scalarmult_ed25519(CLMPD, p) == _p # ed25519 scalar multiplication sets the least three significant # bits of the first octet to zero; therefore: assert c.crypto_scalarmult_ed25519(MIN_P1, p) == _p assert c.crypto_scalarmult_ed25519(MIN_P7, p) == _p _p8 = _p for i in range(8): _p8 = c.crypto_core_ed25519_add(_p8, p) # at this point _p is (2^254 + 16) times p assert c.crypto_scalarmult_ed25519(MIN_P8, p) == _p8
def test_scalarmult_ed25519(): SCALARBYTES = c.crypto_scalarmult_ed25519_SCALARBYTES # the minimum ed25519 scalar is represented by a 8 value in the # first octet, a 64 value in the last octet, and all zeros # in between: MINSC = bytes(bytearray([8] + (SCALARBYTES - 2) * [0] + [64])) # the scalar multiplication formula for ed25519 # "clamps" the scalar by setting the most significant bit # of the last octet to zero, therefore scalar multiplication # by CLMPD is equivalent to scalar multiplication by MINSC CLMPD = bytes(bytearray([8] + (SCALARBYTES - 2) * [0] + [192])) MIN_P1 = bytes(bytearray([9] + (SCALARBYTES - 2) * [0] + [64])) MIN_P7 = bytes(bytearray([15] + (SCALARBYTES - 2) * [0] + [64])) MIN_P8 = bytes(bytearray([16] + (SCALARBYTES - 2) * [0] + [64])) p, _s = c.crypto_sign_keypair() _p = p for i in range(254): # double _p _p = c.crypto_core_ed25519_add(_p, _p) for i in range(8): _p = c.crypto_core_ed25519_add(_p, p) # at this point _p is (2^254+8) times p assert c.crypto_scalarmult_ed25519(MINSC, p) == _p assert c.crypto_scalarmult_ed25519(CLMPD, p) == _p # ed25519 scalar multiplication sets the least three significant # bits of the first octet to zero; therefore: assert c.crypto_scalarmult_ed25519(MIN_P1, p) == _p assert c.crypto_scalarmult_ed25519(MIN_P7, p) == _p _p8 = _p for i in range(8): _p8 = c.crypto_core_ed25519_add(_p8, p) # at this point _p is (2^254 + 16) times p assert c.crypto_scalarmult_ed25519(MIN_P8, p) == _p8
def getRequestOTKey(self, entryIndex: str) -> bytes: """ Given the index of an entry of interest to the Receiver, returns the tailored public Oblivious Transfer key of the Receiver. Further, the Oblivious Transfer secret key is stored internally, which later is used to decrypt the entry of interest to the Receiver. :param entryIndex: The index of an entry of interest to the Receiver. It must be provided as a string. """ entryIndexBytes = entryIndex.encode('utf8') sk = nacl.utils.random(crypto_scalarmult_ed25519_SCALARBYTES) pk = crypto_scalarmult_ed25519_base(sk) self.__otSecrets[entryIndex] = crypto_scalarmult_ed25519( sk, self.__senderOTKey) return crypto_core_ed25519_add( crypto_scalarmult_ed25519( b'\0' * (32 - len(entryIndexBytes)) + entryIndexBytes, self.__senderOTKey), pk)
def __init__(self) -> None: """ Initialises the Sender. """ self.__senderOTSecret = nacl.utils.random( #bytes(random.getrandbits(8) for _ in range( crypto_scalarmult_ed25519_SCALARBYTES) #) self.__senderOTKey = crypto_scalarmult_ed25519_base( self.__senderOTSecret) self.__senderOTU = crypto_scalarmult_ed25519(self.__senderOTSecret, self.__senderOTKey)
def retrieve(self, params: dict) -> dict: """ Returns all encrypted entries provided to the Sender (usually all entries of a database). It should contain the entry of interest to the Receiver, although the Sender is unaware of which entry is the one. Each entry must be a python dict containing the following keys: 'index' as the index of the entry given by a string, 'value' as the value of the entry given by a string. All entries will be extended with a new key, which must be calculated only once per Sender instance: 'indexOTU' as a specific Oblivious Transfer index value calculated in dependence of the senderOTKey. :param params: A python dict containing the following: 'requestOTKey' as the tailored public Oblivious Transfer key of the Receiver, 'entries' with a list of all entries to be sent to the Receiver. """ sharedOTSecret = crypto_scalarmult_ed25519(self.__senderOTSecret, params['requestOTKey']) C = {} for entry in params['entries']: entryIndexBytes = entry['index'].encode('utf8') try: tmp = entry['indexOTU'] except: entry['indexOTU'] = crypto_scalarmult_ed25519( b'\0' * (32 - len(entryIndexBytes)) + entryIndexBytes, self.__senderOTU) K = crypto_core_ed25519_sub(sharedOTSecret, entry['indexOTU']) c = nacl.secret.SecretBox(K).encrypt(entry['value'].encode('utf8')) if CONCEAL_RESPONSE_INDICES: i = _calcMac( entryIndexBytes, keyBytes=K, ) else: i = entry['index'] C[i] = c return C
def test_scalarmult_ed25519_base(): """ Verify scalarmult_ed25519_base is congruent to scalarmult_ed25519 on the ed25519 base point """ BASEPOINT = bytes( bytearray([ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, ])) sclr = c.randombytes(c.crypto_scalarmult_ed25519_SCALARBYTES) p = c.crypto_scalarmult_ed25519_base(sclr) p2 = c.crypto_scalarmult_ed25519(sclr, BASEPOINT) assert p2 == p
def test_scalarmult_ed25519_base(): """ Verify scalarmult_ed25519_base is congruent to scalarmult_ed25519 on the ed25519 base point """ BASEPOINT = bytes(bytearray([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66] ) ) sclr = c.randombytes(c.crypto_scalarmult_ed25519_SCALARBYTES) p = c.crypto_scalarmult_ed25519_base(sclr) p2 = c.crypto_scalarmult_ed25519(sclr, BASEPOINT) assert p2 == p