aboutsummaryrefslogblamecommitdiff
path: root/src/crypto/crypto.h
blob: 2dd2085ceffce575bda1b4487ed3876603af93d3 (plain) (tree)





































































































































































                                                                                                                                                       
#pragma once

#include <cstddef>
#include <cstring>

namespace crypto {

#pragma pack(push, 1)
  class hash {
    char data[32];
  };

  class ec_point {
    char data[32];
  };

  class ec_scalar {
    char data[32];
  };

  class public_key: ec_point {
    friend class crypto_ops;
  };

  class secret_key: ec_scalar {
    friend class crypto_ops;
  };

  class key_image: ec_point {
    friend class crypto_ops;
  };

  class signature {
    ec_scalar c, r;
    friend class crypto_ops;
  };
#pragma pack(pop)

  static_assert(sizeof(hash) == 32 && sizeof(ec_point) == 32 &&
    sizeof(ec_scalar) == 32 && sizeof(public_key) == 32 &&
    sizeof(secret_key) == 32 && sizeof(key_image) == 32 &&
    sizeof(signature) == 64, "Invalid structure size");

  extern "C" {
    void keccak(const void *data, std::size_t length, char *hash);
  }

  inline void keccak(const void *data, std::size_t length, hash &hash) {
    keccak(data, length, reinterpret_cast<char *>(&hash));
  }

  inline bool operator==(const hash &a, const hash &b) {
    return std::memcmp(&a, &b, sizeof(struct hash)) == 0;
  }

  inline bool operator==(const public_key &a, const public_key &b) {
    return std::memcmp(&a, &b, sizeof(struct public_key)) == 0;
  }

  inline bool operator==(const key_image &a, const key_image &b) {
    return std::memcmp(&a, &b, sizeof(struct key_image)) == 0;
  }

  class crypto_ops {
    crypto_ops();
    crypto_ops(const crypto_ops &);
    void operator=(const crypto_ops &);
    ~crypto_ops();

    static void generate_keys(public_key &, secret_key &);
    friend void generate_keys(public_key &, secret_key &);
    static bool check_key(const public_key &);
    friend bool check_key(const public_key &);
    static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
    friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
    static bool check_signature(const hash &, const public_key &, const signature &);
    friend bool check_signature(const hash &, const public_key &, const signature &);
    static void generate_key_image(const public_key &, const secret_key &, key_image &);
    friend void generate_key_image(const public_key &, const secret_key &, key_image &);
    static void generate_ring_signature(const hash &, const key_image &,
      const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
    friend void generate_ring_signature(const hash &, const key_image &,
      const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
    static bool check_ring_signature(const hash &, const key_image &,
      const public_key *const *, std::size_t, const signature *);
    friend bool check_ring_signature(const hash &, const key_image &,
      const public_key *const *, std::size_t, const signature *);
  };

  /* Generate a new key pair.
   * pub: a newly generated public key.
   * sec: a newly generated secret key.
   */
  inline void generate_keys(public_key &pub, secret_key &sec) {
    crypto_ops::generate_keys(pub, sec);
  }

  /* Check a public key.
   * key: a key to check.
   * returns: true if the key is valid, false otherwise.
   */
  inline bool check_key(const public_key &key) {
    return crypto_ops::check_key(key);
  }

  /* Sign a message.
   * message_hash: hash of a message.
   * pub: public key used for signing. Assumed to be valid.
   * sec: secret key used for signing. Assumed to correspond to pub.
   * sig: the resulting signature.
   */
  inline void generate_signature(const hash &message_hash, const public_key &pub, const secret_key &sec, signature &sig) {
    crypto_ops::generate_signature(message_hash, pub, sec, sig);
  }

  /* Verify a signature.
   * message_hash: hash of a message.
   * pub: public key used for signing. Assumed to be valid, use check_key to check it first.
   * sig: a signature.
   * returns: true if the signature is valid, false otherwise.
   */
  inline bool check_signature(const hash &message_hash, const public_key &pub, const signature &sig) {
    return crypto_ops::check_signature(message_hash, pub, sig);
  }

  /* Generate the image of a key.
   * pub: public key used for signing. Assumed to be valid.
   * sec: secret key used for signing. Assumed to correspond to pub.
   * image: the resulting key image.
   */
  inline void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
    crypto_ops::generate_key_image(pub, sec, image);
  }

  /* Sign a message using linkable ring signature.
   * message_hash: hash of a message.
   * image: image of the key used for signing. Use generate_key_image to create it. Assumed to correspond to the key used for signing.
   * pubs: pointer to an array of pointers to public keys of a ring. All keys are assumed to be valid, use check_key to check them first.
   * pubs_count: number of keys in a ring.
   * sec: secret key used for signing.
   * sec_index: index of the key used for signing in pubs. It is assumed that 0 <= sec_index < pubs_count and that sec corresponds to *pubs[sec_index].
   * sig: the resulting signature (occupies pubs_count elements). To verify it, image of the key is also necessary.
   */
  inline void generate_ring_signature(const hash &message_hash, const key_image &image,
    const public_key *const *pubs, std::size_t pubs_count,
    const secret_key &sec, std::size_t sec_index,
    signature *sig) {
    crypto_ops::generate_ring_signature(message_hash, image, pubs, pubs_count, sec, sec_index, sig);
  }

  /* Verify a linkable ring signature.
   * message_hash: hash of a message.
   * image: image of the key used for signing.
   * pubs: pointer to an array of pointers to public keys of a ring. All keys are assumed to be valid, use check_key to check them first.
   * pubs_count: number of keys in a ring.
   * sig: a signature (occupies pubs_count elements).
   * returns: true if the signature is valid, false otherwise.
   */
  inline bool check_ring_signature(const hash &message_hash, const key_image &image,
    const public_key *const *pubs, std::size_t pubs_count,
    const signature *sig) {
    return crypto_ops::check_ring_signature(message_hash, image, pubs, pubs_count, sig);
  }

  /* To check whether two signatures are linked, compare their key images. */
}