How would you convert a string to a 64 bit integer? - java

I am making an application that involves a seed to generate a world and some games let you provide that seed with text. I'm wondering how would you 'convert' a string to an integer.
A simple way would be to use the ASCII values of all the characters and append them to a string which you would then parse to an integer, but that severely limits the size of the string. How would you be able to do this with a larger string?
EDIT: 64 bit not 32

I would just call String.hashcode(). The standard String.hashcode() function makes use of all characters in the target string and gives good dispersal.
The only thing I would question is whether 32 bits of seed is going to be enough. It might mean that your world generator could generate at most 232 different worlds.

Random seeds for Random can be at least 48-bit, ideally 64-bit. You can write your own hash code like this.
public static long hashFor(String s) {
long h = 0;
for(int i = 0; i < s.length(); i++)
h = h * 10191 + s.charAt(i);
return h;
}

The Standard way for converting a String to Integer is using Integer.parseInt(String);
You pass the string into this and it would convert the String to int. Try it and let me know!

Related

Java hashcode brute-forcing [duplicate]

Is there any way that I can use a hashcode of a string in java, and recreate that string?
e.g. something like this:
String myNewstring = StringUtils.createFromHashCode("Hello World".hashCode());
if (!myNewstring.equals("Hello World"))
System.out.println("Hmm, something went wrong: " + myNewstring);
I say this, because I must turn a string into an integer value, and reconstruct that string from that integer value.
This is impossible. The hash code for String is lossy; many String values will result in the same hash code. An integer has 32 bit positions and each position has two values. There's no way to map even just the 32-character strings (for instance) (each character having lots of possibilities) into 32 bits without collisions. They just won't fit.
If you want to use arbitrary precision arithmetic (say, BigInteger), then you can just take each character as an integer and concatenate them all together. VoilĂ .
No. Multiple Strings can have the same hash code. In theory you could create all the Strings that have have that hash code, but it would be near infinite.
Impossible I'm afraid. Think about it, a hashcode is a long value i.e. 8 bytes. A string maybe less than this but also could be much longer, you cannot squeeze a longer string into 8 bytes without losing something.
The Java hashcode algorithm sums every 8th byte if I remember correctly so you'd lose 7 out of 8 bytes. If your strings are all very short then you could encode them as an int or a long without losing anything.
For example, "1019744689" and "123926772" both have a hashcode of -1727003481. This proves that for any integer, you might get a different result (i.e. reversehashcode(hashcode(string)) != string).
Let's assume the string consists only of letters, digits and punctuation, so there are about 70 possible characters.
log_70{2^32} = 5.22...
This means for any given integer you will find a 5- or 6-character string with this as its hash code. So, retrieving "Hello World": impossible; but "Hello" might work if you're lucky.
You could do something like this:
char[] chars = "String here".toCharArray();
int[] ints = new int[chars.length];
for (int i = 0; i < chars.length; i++) {
ints[i] = (int)chars[i];
}
Then:
char[] chars = new char[ints.length]
for (int i = 0; i < chars.length; i++) {
chars[i] = (char)ints[i];
}
String final = new String(chars);
I have not actually tested this yet... It is just "concept" code.

hash string at hash number java

Hiii,I need to do the opposite of what my hash method does, I want a number to convert it to a string, unlike my other method.
I need you to do it in the same way coding as decoding
That would only be possible if there was a 1 to 1 mapping between Strings and longs. Since there are 264 possible long values, and many many more possible String values (even if you limit yourself to Strings of 64 characters, there are still K64 of them, where K is the number of possible unique characters), there cannot be a method that reverses your long hash(String c) method for all possible Strings.
I think that you are trying to implement the Vigenère cipher.
I have fixed your code for executing the two functions (hash and hash2) and I have noticed that hash("javaguay") returns the long number 2485697837967351 and then hash2(2485697837967351L) returns yaugavaj, the reverse string that you want.
A quick response could be the next, but I think you must fix your algorithm.
Add these lines to the end hash2 function:
String res2 = "";
for (int i = res.length() -1; i >=0; i--) {
res2 += res.charAt(i);
}
return res2;

How do you make a byte into a binary number and not to a string in java

When I want to print the binary number of a byte, I have to do:
byte byte1 = 16;
String byteString = Integer.toBinaryString(byte1);
System.out.println(byteString);
This makes the byte into a string, but when I try to parse it into a byte, it makes it into a base 10 number again, Is there a way to make a byte into a binary number byte, and not to a base-10? I want to make it so that if you printed the byte, it would print the binary. do you have to tell it to print the Binary every time?
I want to know if there is a way to make it print the binary representation of the byte every time, instead of having to convert it to a binary string every time, and without making a new string variable to print.
You don't need a String variable because you can just do this:
System.out.println(Integer.toBinaryString(a));
but there is no way to make the conversion happen automatically without using toBinaryString. If this code is too long, you could make a simple method like this
public static void printInBinary(int a) {
System.out.println(Integer.toBinaryString(a));
}
As you have identified, both approaches will result in unnecessary work if you need to print the same number repeatedly, but you do not need to worry about this. Worrying about stuff like that is a waste of time (99% of the time).
Because of programmer efficiency.
At physical level, computers do not have the concept of neither "binary" numbers nor "decimal" numbers (I mean, in form of "110011" or "123"). It's all electrical impulses in there. When you are printing a number onto the screen, it ALWAYS has to convert the "impulses" into characters on your screen in one way or another.
When the number is stored in memory as a "number", it is not compatible with neither decimal nor binary representation. Converting the "number" into a "string" of any kind requires approximately same amount of computing power.
Let's say you have this code:
byte byte1 = 16;
String byteString = Integer.toBinaryString(byte1);
System.out.println(byteString);
System.out.println(byte1);
In reality, the operations performed by the cpu would look something like this:
String byteString = Integer.toBinaryString(byte1);
String decimalString = toDecimalString(byte1);
System.out.println(byteString);
System.out.println(decimalString);
That is, unless you save your number as String already, your CPU has to do extra work to convert it into either decimal or hexadecimal or binary representation. It is just that by default a decimal representation is chosen. And, there is no way to somehow "switch" this default representation neither for one variable nor globally for entire application.
Therefore, you need to convert it to binary every time you want a variable of any numeric type printed on the screen as a character.
What about Byte.parseByte(s, radix)?
System.out.println(Byte.parseByte("10000", 2)); // prints 16
What about this:
byte byte1 = 76;
StringBuilder byteString = new StringBuilder();
for (int i = 128; i > 0; i /= 2) {
if ((byte1 & i) == 0) {
byteString.append(0);
} else {
byteString.append(1);
}
}
System.out.println(byteString);

How to convert Parse ObjectId (String) to long?

Every object in Parse.com has your own ObjectId, that is a string with 10 char and apparently it is created by this regex: [0-9a-zA-Z]{10}.
Example of ObjectId in Parse:
X12wEq4sFf
Weg243d21s
zwg34GdsWE
I would like to convert this String to Long, because it will save memory and improve searching. (10 chars using UTF-8 has 40 bytes, and 1 long has 8 bytes)
If we calculate the combinations, we can find:
String ObjectId: 62^10 = 839299365868340224 different values;
long: is 2^64 = 18446744073709551616 different values.
So, we can convert these values without losing information. There is a simple way to do it safely? Please, consider any kind of encoding for Chars (UTF-8, UTF-16, etc);
EDIT: I am just thinking in a hard way to solved it. I am asking if there is an easy way.
Your character set is a subset of the commonly-used Base64 encoding, so you could just use that. Java has the Base64 class, no need to roll your own codec for this.
Are you sure this is actually valuable? "because it will save memory and improve searching" seems like an untested assertion; saving a few bytes on the IDs may very well be offset by the added cost of encoding and decoding every time you want to use something.
EDIT: Also, why are you using UTF-8 strings for guaranteed-ascii data? If you represent 10 char IDs as a byte[10], that's just 10 bytes instead of 40 (i.e. much closer to the 8 for a long). And you don't need to do any fancy conversions.
Here's a straightforward solution using 6 bits to store a single character.
public class Converter {
private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static int convertChar(char c) {
int ret = CHARS.indexOf( c );
if (ret == -1)
throw new IllegalArgumentException( "Invalid character encountered: "+c);
return ret;
}
public static long convert(String s) {
if (s.length() != 10)
throw new IllegalArgumentException( "String length must be 10, was "+s.length() );
long ret = 0;
for (int i = 0; i < s.length(); i++) {
ret = (ret << 6) + convertChar( s.charAt( i ));
}
return ret;
}
}
I'll leave the conversion from long to String for you to implement, it's basically the same in reverse.
P.s.: If you really want to save space, don't use Long, it adds nothing compared to the primitive long except overhead.
P.s 2: Also note that you aren't really saving much with this conversion: storing the ASCII characters can be done in 10 bytes, while a long takes up 4. What you save here is mostly the overhead you'd get if you stored those 10 bytes in a byte array.

Standard way to create a hash in Java

The question is about the correct way of creating a hash in Java:
Lets assume I have a positive BigInteger value that I would like to create a hash from. Lets assume that below instance of the messageDigest is a valid instance of (SHA-256)
public static final BigInteger B = new BigInteger("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58", 16);
byte[] byteArrayBBigInt = B.toByteArray();
this.printArray(byteArrayBBigInt);
messageDigest.reset();
messageDigest.update(byteArrayBBigInt);
byte[] outputBBigInt = messageDigest.digest();
Now I only assume that the code below is correct, as according to the test the hashes I produce match with the one produced by:
http://www.fileformat.info/tool/hash.htm?hex=BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58
However I am not sure why we are doing the step below i.e.
because the returned byte array after the digest() call is signed and in this case it is a negative, I suspect that we do need to convert it to a positive number i.e. we can use a function like that.
public static String byteArrayToHexString(byte[] b) {
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
thus:
String hex = byteArrayToHexString(outputBBigInt)
BigInteger unsignedBigInteger = new BigInteger(hex, 16);
When I construct a BigInteger from the new hex string and convert it back to byte array then I see that the sign bit, that is most significant bit i.e. the leftmost bit, is set to 0 which means that the number is positive, moreover the whole byte is constructed from zeros ( 00000000 ).
My question is: Is there any RFC that describes why do we need to convert the hash always to a "positive" unsigned byte array. I mean even if the number produced after the digest call is negative it is still a valid hash, right? thus why do we need that additional procedure. Basically, I am looking for a paper: standard or rfc describing that we need to do so.
A hash consists of an octet string (called a byte array in Java). How you convert it to or from a large number (a BigInteger in Java) is completely out of the scope for cryptographic hash algorithms. So no, there is no RFC to describe it as there is (usually) no reason to treat a hash as a number. In that sense a cryptographic hash is rather different from Object.hashCode().
That you can only treat hexadecimals as unsigned is a bit of an issue, but if you really want to then you can first convert it back to a byte array, and then perform new BigInteger(result). That constructor does threat the encoding within result as signed. Note that in protocols it is often not needed to convert back and forth to hexadecimals; hexadecimals are mainly for human consumption, a computer is fine with bytes.

Categories