public PrivateKey decodePrivateKey(byte[] k) {
    // magic
    if (k[0] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[0]
          || k[1] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[1]
          || k[2] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[2]
          || k[3] != Registry.MAGIC_RAW_DH_PRIVATE_KEY[3]) {
       throw new IllegalArgumentException("magic");
    }

    // version
    if (k[4] != 0x01) {
       throw new IllegalArgumentException("version");
    }
    int i = 5;
    int l;
    byte[] buffer;

    // q
    l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 | (k[i++] & 0xFF);
    buffer = new byte[l];
    System.arraycopy(k, i, buffer, 0, l);
    i += l;
    BigInteger q = new BigInteger(1, buffer);

    // p
    l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 | (k[i++] & 0xFF);
    buffer = new byte[l];
    System.arraycopy(k, i, buffer, 0, l);
    i += l;
    BigInteger p = new BigInteger(1, buffer);

    // g
    l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 | (k[i++] & 0xFF);
    buffer = new byte[l];
    System.arraycopy(k, i, buffer, 0, l);
    i += l;
    BigInteger g = new BigInteger(1, buffer);

    // x
    l = k[i++] << 24 | (k[i++] & 0xFF) << 16 | (k[i++] & 0xFF) << 8 | (k[i++] & 0xFF);
    buffer = new byte[l];
    System.arraycopy(k, i, buffer, 0, l);
    i += l;
    BigInteger x = new BigInteger(1, buffer);

    return new GnuDHPrivateKey(q, p, g, x);
   }