2016-03-31 21:18:36 -07:00
|
|
|
/*
|
|
|
|
See the Zcash protocol specification for more information.
|
|
|
|
https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef ZC_NOTE_ENCRYPTION_H_
|
|
|
|
#define ZC_NOTE_ENCRYPTION_H_
|
|
|
|
|
|
|
|
#include "uint256.h"
|
2016-05-16 08:50:31 -07:00
|
|
|
#include "uint252.h"
|
2016-03-31 21:18:36 -07:00
|
|
|
|
2016-05-04 17:25:38 -07:00
|
|
|
#include "zcash/Zcash.h"
|
2018-06-14 10:58:45 -07:00
|
|
|
#include "zcash/Address.hpp"
|
2016-03-31 21:18:36 -07:00
|
|
|
|
2018-05-03 03:53:51 -07:00
|
|
|
#include <array>
|
|
|
|
|
2016-03-31 21:18:36 -07:00
|
|
|
namespace libzcash {
|
|
|
|
|
2018-06-14 10:58:45 -07:00
|
|
|
// Ciphertext for the recipient to decrypt
|
|
|
|
typedef std::array<unsigned char, ZC_SAPLING_ENCCIPHERTEXT_SIZE> SaplingEncCiphertext;
|
|
|
|
typedef std::array<unsigned char, ZC_SAPLING_ENCPLAINTEXT_SIZE> SaplingEncPlaintext;
|
|
|
|
|
|
|
|
// Ciphertext for outgoing viewing key to decrypt
|
|
|
|
typedef std::array<unsigned char, ZC_SAPLING_OUTCIPHERTEXT_SIZE> SaplingOutCiphertext;
|
|
|
|
typedef std::array<unsigned char, ZC_SAPLING_OUTPLAINTEXT_SIZE> SaplingOutPlaintext;
|
|
|
|
|
2018-07-11 14:48:41 -07:00
|
|
|
//! This is not a thread-safe API.
|
2018-06-14 10:58:45 -07:00
|
|
|
class SaplingNoteEncryption {
|
|
|
|
protected:
|
|
|
|
// Ephemeral public key
|
|
|
|
uint256 epk;
|
|
|
|
|
|
|
|
// Ephemeral secret key
|
|
|
|
uint256 esk;
|
|
|
|
|
2018-06-14 11:21:28 -07:00
|
|
|
bool already_encrypted_enc;
|
|
|
|
bool already_encrypted_out;
|
|
|
|
|
|
|
|
SaplingNoteEncryption(uint256 epk, uint256 esk) : epk(epk), esk(esk), already_encrypted_enc(false), already_encrypted_out(false) {
|
2018-06-14 10:58:45 -07:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2020-07-02 08:24:03 -07:00
|
|
|
static boost::optional<SaplingNoteEncryption> FromDiversifier(diversifier_t d, uint256 esk);
|
2018-06-14 10:58:45 -07:00
|
|
|
|
|
|
|
boost::optional<SaplingEncCiphertext> encrypt_to_recipient(
|
|
|
|
const uint256 &pk_d,
|
|
|
|
const SaplingEncPlaintext &message
|
|
|
|
);
|
|
|
|
|
|
|
|
SaplingOutCiphertext encrypt_to_ourselves(
|
|
|
|
const uint256 &ovk,
|
|
|
|
const uint256 &cv,
|
|
|
|
const uint256 &cm,
|
|
|
|
const SaplingOutPlaintext &message
|
|
|
|
);
|
|
|
|
|
|
|
|
uint256 get_epk() const {
|
|
|
|
return epk;
|
|
|
|
}
|
2018-06-18 12:14:43 -07:00
|
|
|
|
|
|
|
uint256 get_esk() const {
|
|
|
|
return esk;
|
|
|
|
}
|
2018-06-14 10:58:45 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// Attempts to decrypt a Sapling note. This will not check that the contents
|
|
|
|
// of the ciphertext are correct.
|
|
|
|
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption(
|
|
|
|
const SaplingEncCiphertext &ciphertext,
|
|
|
|
const uint256 &ivk,
|
|
|
|
const uint256 &epk
|
|
|
|
);
|
|
|
|
|
2018-07-23 10:48:26 -07:00
|
|
|
// Attempts to decrypt a Sapling note using outgoing plaintext.
|
2018-07-20 16:31:48 -07:00
|
|
|
// This will not check that the contents of the ciphertext are correct.
|
2018-07-23 10:48:26 -07:00
|
|
|
boost::optional<SaplingEncPlaintext> AttemptSaplingEncDecryption (
|
2018-07-20 16:31:48 -07:00
|
|
|
const SaplingEncCiphertext &ciphertext,
|
|
|
|
const uint256 &epk,
|
|
|
|
const uint256 &esk,
|
|
|
|
const uint256 &pk_d
|
|
|
|
);
|
|
|
|
|
2018-06-14 10:58:45 -07:00
|
|
|
// Attempts to decrypt a Sapling note. This will not check that the contents
|
|
|
|
// of the ciphertext are correct.
|
|
|
|
boost::optional<SaplingOutPlaintext> AttemptSaplingOutDecryption(
|
|
|
|
const SaplingOutCiphertext &ciphertext,
|
|
|
|
const uint256 &ovk,
|
|
|
|
const uint256 &cv,
|
|
|
|
const uint256 &cm,
|
|
|
|
const uint256 &epk
|
|
|
|
);
|
2016-03-31 21:18:36 -07:00
|
|
|
|
|
|
|
template<size_t MLEN>
|
|
|
|
class NoteEncryption {
|
|
|
|
protected:
|
|
|
|
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
|
|
|
|
uint256 epk;
|
|
|
|
uint256 esk;
|
|
|
|
unsigned char nonce;
|
|
|
|
uint256 hSig;
|
|
|
|
|
|
|
|
public:
|
2018-05-03 03:53:51 -07:00
|
|
|
typedef std::array<unsigned char, CLEN> Ciphertext;
|
|
|
|
typedef std::array<unsigned char, MLEN> Plaintext;
|
2016-03-31 21:18:36 -07:00
|
|
|
|
|
|
|
NoteEncryption(uint256 hSig);
|
|
|
|
|
2017-11-14 13:29:05 -08:00
|
|
|
// Gets the ephemeral secret key
|
|
|
|
uint256 get_esk() {
|
|
|
|
return esk;
|
|
|
|
}
|
|
|
|
|
2016-03-31 21:18:36 -07:00
|
|
|
// Gets the ephemeral public key
|
|
|
|
uint256 get_epk() {
|
|
|
|
return epk;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encrypts `message` with `pk_enc` and returns the ciphertext.
|
2016-08-18 14:51:15 -07:00
|
|
|
// This is only called ZC_NUM_JS_OUTPUTS times for a given instantiation;
|
2016-08-11 11:48:47 -07:00
|
|
|
// but can be called 255 times before the nonce-space runs out.
|
2016-03-31 21:18:36 -07:00
|
|
|
Ciphertext encrypt(const uint256 &pk_enc,
|
|
|
|
const Plaintext &message
|
|
|
|
);
|
|
|
|
|
|
|
|
// Creates a NoteEncryption private key
|
2016-05-16 08:50:31 -07:00
|
|
|
static uint256 generate_privkey(const uint252 &a_sk);
|
2016-03-31 21:18:36 -07:00
|
|
|
|
|
|
|
// Creates a NoteEncryption public key from a private key
|
|
|
|
static uint256 generate_pubkey(const uint256 &sk_enc);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<size_t MLEN>
|
|
|
|
class NoteDecryption {
|
|
|
|
protected:
|
|
|
|
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
|
|
|
|
uint256 sk_enc;
|
|
|
|
uint256 pk_enc;
|
|
|
|
|
|
|
|
public:
|
2018-05-03 03:53:51 -07:00
|
|
|
typedef std::array<unsigned char, CLEN> Ciphertext;
|
|
|
|
typedef std::array<unsigned char, MLEN> Plaintext;
|
2016-03-31 21:18:36 -07:00
|
|
|
|
2016-08-23 20:50:45 -07:00
|
|
|
NoteDecryption() { }
|
2016-03-31 21:18:36 -07:00
|
|
|
NoteDecryption(uint256 sk_enc);
|
|
|
|
|
|
|
|
Plaintext decrypt(const Ciphertext &ciphertext,
|
|
|
|
const uint256 &epk,
|
|
|
|
const uint256 &hSig,
|
|
|
|
unsigned char nonce
|
|
|
|
) const;
|
2016-08-23 20:50:45 -07:00
|
|
|
|
2016-08-31 16:38:43 -07:00
|
|
|
friend inline bool operator==(const NoteDecryption& a, const NoteDecryption& b) {
|
|
|
|
return a.sk_enc == b.sk_enc && a.pk_enc == b.pk_enc;
|
|
|
|
}
|
|
|
|
friend inline bool operator<(const NoteDecryption& a, const NoteDecryption& b) {
|
|
|
|
return (a.sk_enc < b.sk_enc ||
|
|
|
|
(a.sk_enc == b.sk_enc && a.pk_enc < b.pk_enc));
|
|
|
|
}
|
2016-03-31 21:18:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
uint256 random_uint256();
|
2016-05-16 08:50:31 -07:00
|
|
|
uint252 random_uint252();
|
2016-03-31 21:18:36 -07:00
|
|
|
|
2017-01-31 13:55:10 -08:00
|
|
|
class note_decryption_failed : public std::runtime_error {
|
|
|
|
public:
|
|
|
|
note_decryption_failed() : std::runtime_error("Could not decrypt message") { }
|
|
|
|
};
|
|
|
|
|
2017-11-14 13:29:05 -08:00
|
|
|
|
|
|
|
|
|
|
|
// Subclass PaymentDisclosureNoteDecryption provides a method to decrypt a note with esk.
|
|
|
|
template<size_t MLEN>
|
|
|
|
class PaymentDisclosureNoteDecryption : public NoteDecryption<MLEN> {
|
|
|
|
protected:
|
|
|
|
public:
|
|
|
|
enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES };
|
2018-05-03 03:53:51 -07:00
|
|
|
typedef std::array<unsigned char, CLEN> Ciphertext;
|
|
|
|
typedef std::array<unsigned char, MLEN> Plaintext;
|
2017-11-14 13:29:05 -08:00
|
|
|
|
|
|
|
PaymentDisclosureNoteDecryption() : NoteDecryption<MLEN>() {}
|
|
|
|
PaymentDisclosureNoteDecryption(uint256 sk_enc) : NoteDecryption<MLEN>(sk_enc) {}
|
|
|
|
|
|
|
|
Plaintext decryptWithEsk(
|
|
|
|
const Ciphertext &ciphertext,
|
|
|
|
const uint256 &pk_enc,
|
|
|
|
const uint256 &esk,
|
|
|
|
const uint256 &hSig,
|
|
|
|
unsigned char nonce
|
|
|
|
) const;
|
|
|
|
};
|
|
|
|
|
2016-03-31 21:18:36 -07:00
|
|
|
}
|
|
|
|
|
2016-08-15 07:54:42 -07:00
|
|
|
typedef libzcash::NoteEncryption<ZC_NOTEPLAINTEXT_SIZE> ZCNoteEncryption;
|
|
|
|
typedef libzcash::NoteDecryption<ZC_NOTEPLAINTEXT_SIZE> ZCNoteDecryption;
|
2016-03-31 21:18:36 -07:00
|
|
|
|
2017-11-14 13:29:05 -08:00
|
|
|
typedef libzcash::PaymentDisclosureNoteDecryption<ZC_NOTEPLAINTEXT_SIZE> ZCPaymentDisclosureNoteDecryption;
|
|
|
|
|
2016-05-04 17:25:38 -07:00
|
|
|
#endif /* ZC_NOTE_ENCRYPTION_H_ */
|