content: package im.actor.core.modules.encryption.entity;
  
  import java.io.IOException;
  
  import im.actor.core.api.ApiEncryptionKey;
  import im.actor.core.api.ApiEncryptionKeySignature;
  import im.actor.core.util.RandomUtils;
  import im.actor.runtime.Crypto;
  import im.actor.runtime.bser.BserObject;
  import im.actor.runtime.bser.BserValues;
  import im.actor.runtime.bser.BserWriter;
  import im.actor.runtime.crypto.Curve25519;
  import im.actor.runtime.crypto.Curve25519KeyPair;
  import im.actor.runtime.crypto.primitives.util.ByteStrings;
  import im.actor.runtime.crypto.ratchet.RatchetKeySignature;
  import im.actor.runtime.function.Function;
  import im.actor.runtime.function.Predicate;
  import im.actor.runtime.function.Supplier;
  
  public class PrivateKey extends BserObject {
  
      public static final Predicate<PrivateKey> PRE_KEY_EQUALS(final byte[] publicKey) {
          return new Predicate<PrivateKey>() {
              @Override
              public boolean apply(PrivateKey privateKey) {
                  return ByteStrings.isEquals(publicKey, privateKey.getPublicKey());
              }
          };
      }
  
      public static final Predicate<PrivateKey> PRE_KEY_EQUALS_ID(final long id) {
          return new Predicate<PrivateKey>() {
              @Override
              public boolean apply(PrivateKey privateKey) {
                  return privateKey.getKeyId() == id;
              }
          };
      }
  
      public static final Function<PrivateKey, ApiEncryptionKey> TO_API = new Function<PrivateKey, ApiEncryptionKey>() {
          @Override
          public ApiEncryptionKey apply(PrivateKey privateKey) {
              return privateKey.toApiKey();
          }
      };
  
      public static final Function<PrivateKey, ApiEncryptionKeySignature> SIGN(final PrivateKey identity) {
          return new Function<PrivateKey, ApiEncryptionKeySignature>() {
              @Override
              public ApiEncryptionKeySignature apply(PrivateKey privateKey) {
                  byte[] signature = Curve25519.calculateSignature(Crypto.randomBytes(64), identity.getKey(),
                          RatchetKeySignature.hashForSignature(privateKey.getKeyId(),
                                  privateKey.getKeyAlg(), privateKey.getPublicKey()));
                  return new ApiEncryptionKeySignature(privateKey.getKeyId(), "Ed25519", signature);
              }
          };
      }
  
      public static final Supplier<PrivateKey> GENERATOR = new Supplier<PrivateKey>() {
          @Override
          public PrivateKey get() {
              Curve25519KeyPair keyPair = Curve25519.keyGen(Crypto.randomBytes(64));
              return new PrivateKey(
                      RandomUtils.nextRid(),
                      "curve25519",
                      keyPair.getPrivateKey(),
                      keyPair.getPublicKey(),
                      false);
          }
      };
  
      public static final Predicate<PrivateKey> NOT_UPLOADED = new Predicate<PrivateKey>() {
          @Override
          public boolean apply(PrivateKey privateKey) {
              return !privateKey.isUploaded();
          }
      };
  
      public static final Predicate<PrivateKey> UPLOADED = new Predicate<PrivateKey>() {
          @Override
          public boolean apply(PrivateKey privateKey) {
              return privateKey.isUploaded();
          }
      };
  
      private long keyId;
      private String keyAlg;
      private byte[] key;
      private byte[] publicKey;
      private Boolean isUploaded;
      private boolean wasRegenerated = false;
  
      public PrivateKey(long keyId, String keyAlg, byte[] privateKey, byte[] publicKey, Boolean isUploaded) {
          this.keyId = keyId;
          this.keyAlg = keyAlg;
          this.key = privateKey;
          this.isUploaded = isUploaded;
          this.publicKey = publicKey;
      }
  
      public PrivateKey(long keyId, String keyAlg, byte[] privateKey, byte[] publicKey) {
          this(keyId, keyAlg, privateKey, publicKey, null);
      }
  
      public PrivateKey(byte[] data) throws IOException {
          load(data);
      }
  
      public long getKeyId() {
          return keyId;
      }
  
      public String getKeyAlg() {
          return keyAlg;
      }
  
      public byte[] getKey() {
          return key;
      }
  
      public byte[] getPublicKey() {
          return publicKey;
      }
  
      public boolean isUploaded() {
          if (isUploaded == null) {
              return false;
          }
          return isUploaded;
      }
  
      public boolean isWasRegenerated() {
          return wasRegenerated;
      }
  
      public ApiEncryptionKey toApiKey() {
          return new ApiEncryptionKey(keyId, keyAlg, publicKey, null);
      }
  
      public PrivateKey markAsUploaded() {
          return new PrivateKey(getKeyId(), getKeyAlg(), getKey(), getPublicKey(), true);
      }
  
      @Override
      public void parse(BserValues values) throws IOException {
          keyId = values.getLong(1);
          keyAlg = values.getString(2);
          key = values.getBytes(3);
          isUploaded = values.optBool(4);
          publicKey = values.optBytes(5);
          if (publicKey == null) {
              wasRegenerated = true;
              publicKey = Curve25519.keyGenPublic(key);
          }
      }
  
      @Override
      public void serialize(BserWriter writer) throws IOException {
          writer.writeLong(1, keyId);
          writer.writeString(2, keyAlg);
          writer.writeBytes(3, key);
          writer.writeBytes(5, publicKey);
          if (isUploaded != null) {
              writer.writeBool(4, isUploaded);
          }
      }
  }
  