/**
 * EdDSA-Java by str4d
 *
 * To the extent possible under law, the person who associated CC0 with EdDSA-Java has waived all
 * copyright and related or neighboring rights to EdDSA-Java.
 *
 * You should have received a copy of the CC0 legalcode along with this work. If not, see
 * <https://creativecommons.org/publicdomain/zero/1.0/>.
 */
package org.mariadb.jdbc.internal.com.send.ed25519;

/**
 * Basic utilities for EdDSA. Not for external use, not maintained as a public API.
 *
 * @author str4d
 */
public class Utils {

  /**
   * Constant-time byte comparison.
   *
   * @param b a byte
   * @param c a byte
   * @return 1 if b and c are equal, 0 otherwise.
   */
  public static int equal(int b, int c) {
    int result = 0;
    int xor = b ^ c;
    for (int i = 0; i < 8; i++) {
      result |= xor >> i;
    }
    return (result ^ 0x01) & 0x01;
  }

  /**
   * Constant-time byte[] comparison.
   *
   * @param b a byte[]
   * @param c a byte[]
   * @return 1 if b and c are equal, 0 otherwise.
   */
  public static int equal(byte[] b, byte[] c) {
    int result = 0;
    for (int i = 0; i < 32; i++) {
      result |= b[i] ^ c[i];
    }

    return equal(result, 0);
  }

  /**
   * Constant-time determine if byte is negative.
   *
   * @param b the byte to check.
   * @return 1 if the byte is negative, 0 otherwise.
   */
  public static int negative(int b) {
    return (b >> 8) & 1;
  }

  /**
   * Get the i'th bit of a byte array.
   *
   * @param h the byte array.
   * @param i the bit index.
   * @return 0 or 1, the value of the i'th bit in h
   */
  public static int bit(byte[] h, int i) {
    return (h[i >> 3] >> (i & 7)) & 1;
  }

  /**
   * Converts a hex string to bytes.
   *
   * @param s the hex string to be converted.
   * @return the byte[]
   */
  public static byte[] hexToBytes(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
      data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
          + Character.digit(s.charAt(i + 1), 16));
    }
    return data;
  }

  /**
   * Converts bytes to a hex string.
   *
   * @param raw the byte[] to be converted.
   * @return the hex representation as a string.
   */
  public static String bytesToHex(byte[] raw) {
    if (raw == null) {
      return null;
    }
    final StringBuilder hex = new StringBuilder(2 * raw.length);
    for (final byte b : raw) {
      hex.append(Character.forDigit((b & 0xF0) >> 4, 16))
          .append(Character.forDigit((b & 0x0F), 16));
    }
    return hex.toString();
  }

}
