2

I'm starting to learn functional programming in javascript. This might be a silly question but what I'm trying to solve a non-pure function written in a functional way.

My question is what strategy should be used to accomplish this in a functional programming paradigm.

const crypto = require('crypto');

const encrypt = (data, publicKey) => {
    if (publicKey === undefined ) throw 'Missing public key.';

    const bufferToEncrypt = Buffer.from(data);
    const encrypted = crypto.publicEncrypt({
        key: publicKey
    }, bufferToEncrypt);

    return encrypted;

};
per.eight
  • 428
  • 7
  • 17
  • @cdhowie What I understand about pure functions is that Its return value is the same for the same arguments. My example above is returning different outputs for the same arguments. – per.eight Sep 04 '19 at 00:02
  • @cdhowie hahaha Yea, I guess you should write an answer. As I am starting to get confused about pure function. lol – per.eight Sep 04 '19 at 00:10
  • I've converted my comments to a proper answer. – cdhowie Sep 04 '19 at 00:18

1 Answers1

4

There's two criteria for being a pure function.

Pure function criterion 1: Calling the function with the same values must always yield the same return value

This is impossible when doing asymmetric encryption because a random session key is generated for each operation. The session key is encrypted with the public key, and then the session key is used to encrypt the payload. The returned value is usually just an encoded version of two values: (1) the pubkey-encrypted session key, and (2) the session key -encrypted payload.

Both of these values are going to be different each time you call the function because the session key is going to be different each time.

However, despite the return values not comparing as equal, I would argue that they are semantically equal -- that is, if you decrypt each value with the matching private key, the decrypted values will compare as equal.

The encryption is effectively obfuscating that the values are equal, and for encryption that's a good thing. We don't want two encrypted messages generated at different times to be compared without having the decryption key. That would be a security risk.

Therefore, I argue that this function semantically meets this criterion but we can't tell without the public key.

Pure function criterion 2: The function has no observable side-effects

This point should be fairly obvious: writing to a disk is a side-effect, writing to a global variable is a side-effect, etc. We should not be able to distinguish any differences in state before and after calling the function.

Technically, generation of the session key is going to require using the system's secure random number generator. This is going to consume some entropy. After running the function, less entropy will be available and this can be measured.

However, I would argue that this side-effect can be disregarded as anything that requires a secure random number is going to have the same problem, and this is more an implementation detail of the secure random number generator.

It would be like claiming that a function that requires a lot of CPU time has a side-effect because running it increases the CPU time counter for the process. Is it a side-effect? Technically... maybe? But no reasonable person would consider that to be a side effect.

Conclusion

I would call this function "semantically pure." If you asked me if this was a pure function and only accepted a yes/no answer with no qualification, I'd tell you "yes."

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • @ cdhowie that make sense. Thanks for making it clear, appreciate it! – per.eight Sep 04 '19 at 00:22
  • 1 & 2 are easily fixed by having the function take a state as a second argument and having a state being returned. Thus the side effects are gone even for runs that takes more than one call. – Sylwester Sep 04 '19 at 00:43
  • @Sylwester I'm not sure how that would be relevant to this specific function. Can you give an example? – cdhowie Sep 04 '19 at 03:22
  • @cdhowie All functions can be rewritten to obey your 2 criteria. Eg. `cryptoWrite(payLoad)` where you get the payload after finished putting values in there. I agree that the OPs function has a functional contract and from an user perspective is impossible to deduce if it's 100% pure or not. – Sylwester Sep 04 '19 at 23:19
  • @Sylwester If you mean passing a continuation into a function, that could be seen as making it non-pure (calling the function provided is a side-effect). If we stipulate that this does not count as a side-effect, it still doesn't change anything about the function, as the value passed to the continuation could be seen as the "return value." If passing a continuation isn't what you're suggesting, then I still don't know what you're trying to say. – cdhowie Sep 04 '19 at 23:24
  • @cdhowie It doesn't need a continuation. It can return a state object that you may pass back to the next iteration. The continuation idea could work as well and it is how Haskell can be used in real life applications and not just as a teaching language. – Sylwester Sep 04 '19 at 23:32
  • @Sylwester Those can certainly work but they don't really change the purity of the function. They just change how the return value gets conveyed to whatever else is going to use it. – cdhowie Sep 04 '19 at 23:34
  • @cdhowie From a function that needs internal state to one that gets state passed as an argument does not change purity? A function that collects something into a file that outsource the accumulation by returning a monad does not change purity? – Sylwester Sep 04 '19 at 23:39
  • @Sylwester The function here does not need internal or external state. Regarding your second question, I'd need to see an example and I'm still not sure how it applies to OP's example. – cdhowie Sep 04 '19 at 23:43
  • @cdhowie Well it has a functional contract so it's as pure as you can get it from OPs question. My comment was that all functions can be rewritten to adhere to the 2 rules of yours. eg a function that writes to a file or a crypt function that takes several turns before returning a encrypted payload. – Sylwester Sep 04 '19 at 23:45