function hascode() in SDK return a different value in new BETA firmware 10.52 for F5X

Hi

In SDK 249 or beta 3 , i make a license by using hascode() function.

Example: var Field="B2604"

System.println(Field.hashCode()) return in SDK 893178341 no change since sdk 1 and other


but in 10.52 new BETA firmware of F5 series it's return 758960613

It's new because in previous production firmware it returns 893178341 same as SDK

Why this change is new BETA firmware for F5 Series same for F5, 935, F5X

it's OK in all production firmware even in F5X plus series, but not in beta firmware for F5 series


Thx
  • Yes, you are noticing a change to the String.hashCode() function that was made in ConnectIQ 3.0. The result of this change is that hash values for some strings may be different from what you would have seen with previous versions of ConnectIQ.

    Our expectation for hashCode() is consistent with that of Java's Object.hashCode() function...

    The general contract of hashCode is:
    • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
    • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
    • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables


    Other languages (like python) have similar requirements.

    The documentation of Object.hashCode() is consistent with this..

    Hash code values have the following characteristics:
    • The computed hash code is constant for the lifetime of an Object
    • If two Objects are equal, their hash codes will be equal


    Unfortunately this doesn't appear in the docs for String.hashCode(), so it isn't immediately obvious that the result of a call to hashCode() could vary across devices or even between different runs on the same device. I'll be adding a blurb to the docs about this.

    Travis
  • This is what I am using as well for my licensing scheme. It has worked well with CIQ 2, but some users with beta CIQ 3 firmware have started complaining, as the watch starts rejecting license codes.
    Very well that you have made the hash-function consistent with the Java definition, but now it's useless for licensing. Is there an alternative function, which does always deliver the same outcome when the input is the same?
    I am thinking of stopping developping for Garmin watches; very disapointing, this behaviour of just changing functions for the sake of changing
  • I use xor function

    example

    number1 = 123456

    crypto = 4567

    Number2=Number1 xor crypto = 987654

    Now

    number2 xor crypto = number1

    when you make 2 xor you return to first number

    with this method you don't use hashcode

    didier
  • Thnx Didier, I will look into it. However, if it works I still have to give out 100+ license keys again, because the behaviour of a function is changed by Garmin.
    Travis : you refer to Python, but with Python there is a better way of dealing with this; one can choose whether to get salted or non-salted results. See: https://stackoverflow.com/questions/27522626/hash-function-in-python-3-3-returns-different-results-between-sessions. Setting PYTHONHASHSEED to zero gives repeatable outcomes.
    Please make that an option!
  • GHG23, As there is already production firmware with the 3.0.1 VM - for the f5 and f5 plus devices that's going out now (10.00 and 4.00) - and I'm sure other devices are coming soon, so even if there is a change, it would take awhile to get released.

    I think you'll need to just switch to something like Didier suggested.

    Also, bear in mind that what you were doing with uniqueIdentifier is device specific, so the same licence wouldn't work on two different devices, say if the user had a Fenix and an Edge, or if the user upgraded from a f5 to an f5+.

  • Is there an alternative function, which does always deliver the same outcome when the input is the same?

    Certainly. You can implement your own hashCode function for string. This one is deterministic and happens to produce the same result as String.hashCode() with ConnectIQ 2.x and earlier.

    // requires ConnectIQ 1.3.x, produces the same hash value regardless
    // of ConnectIQ version.
    function hashCode(string) {
    var val = 0;

    var bytes = string.toUtf8Array();
    for (var i = 0; i < bytes.size(); ++i) {
    val = (val * 997) + bytes;
    }

    return val + (val >> 5);
    }

    using Toybox.Test;

    (:test) function test_hash_code(logger) {
    Test.assertEqual( 0, hashCode(""));
    Test.assertEqual( 50, hashCode("1"));
    Test.assertEqual( 56603, hashCode("75"));
    Test.assertEqual( 104659159, hashCode("fc1"));
    Test.assertEqual( 1401752010, hashCode("e2b8"));
    Test.assertEqual( -1104976049, hashCode("e302d"));
    Test.assertEqual( 554445039, hashCode("622fa6"));
    Test.assertEqual( -1206670715, hashCode("5eec043"));
    Test.assertEqual( -1752770088, hashCode("ab94b772"));
    Test.assertEqual( -1535417709, hashCode("b9516edb7"));
    Test.assertEqual( -1053731146, hashCode("7226da40dc"));
    Test.assertEqual( -2008755386, hashCode("2866150d4ee"));
    Test.assertEqual( -2096588956, hashCode("c9b2f394ad6b"));
    Test.assertEqual( 1365951289, hashCode("d706fe56bcd9a"));
    Test.assertEqual( -1949640431, hashCode("19f824801a8eae"));
    Test.assertEqual( -1189230867, hashCode("066836dad783fb4"));
    Test.assertEqual( 1905094397, hashCode("059ba3488d4f5ef6"));
    Test.assertEqual( -615738654, hashCode("0672b0a196e5706e4"));
    Test.assertEqual( 1951136512, hashCode("c2867bd639c6302cd1"));
    Test.assertEqual( 324542647, hashCode("e22656a7614ac4707c8"));
    Test.assertEqual( -2134186901, hashCode("8dc3b9d5d9bb9cf4d175"));
    Test.assertEqual( -1783825913, hashCode("622e1dd9241f0f1cfd327"));
    Test.assertEqual( 295381559, hashCode("f614b760672b0bb8ea77b4"));
    Test.assertEqual( -1197067832, hashCode("0dc33d707d2025335adeeda"));
    Test.assertEqual( -489771258, hashCode("def7afb40d5c203e83772277"));
    Test.assertEqual( -1220324149, hashCode("b53ab8745cb76908cfc92d71d"));
    Test.assertEqual( -1151775522, hashCode("d0429593f23c4e7b481bb19f8b"));
    Test.assertEqual( 1131950698, hashCode("264cb6c1ea6c8013f386f6837fe"));
    Test.assertEqual( 1584670424, hashCode("db6c05937e45555d885801bb9505"));
    Test.assertEqual( 2065892154, hashCode("9bb0241e311253b8745cbf2b0baaa"));
    Test.assertEqual( 1329262949, hashCode("2fbd782c5462ab86fec059ba3532e9"));
    Test.assertEqual( 257085918, hashCode("12df570f1516ff7af234924808c70e3"));
    Test.assertEqual( 1449995390, hashCode("0b3cc326d3ab8ea644714b7e4d0c6319"));
    Test.assertEqual( 636236195, hashCode("7c17c0588dcacc3a2fb5a53ab02ccbe98"));
    Test.assertEqual( 1683597166, hashCode("d5d8000859a0a9cf57900136dbfa7f6900"));
    Test.assertEqual( 1470292685, hashCode("1bb10967b5bfae1dd0cfd203fb5b7e4cb77"));
    Test.assertEqual( -1148791204, hashCode("2ab9cee5fc81a959a18c783644e698588ce7"));
    Test.assertEqual( 213368485, hashCode("235a404ac4fdb7ec88588cf5706606ff73037"));
    Test.assertEqual( 490874742, hashCode("739c62a3cd89e227edbe1dc2108d4e72aab19e"));
    Test.assertEqual( 687823056, hashCode("ae1d5cbfbd798d5c20bb19eb529dc3349bb87da"));

    // result of your original test scenario run on a 2.4.9 SDK
    Test.assertEqual( -893178341, hashCode("B2604"));

    // another testcase from a different user
    Test.assertEqual( -1579362389, hashCode("94ee97321e81ef7555f83ec693f815acd01ff54e"));

    return true;
    }
    [/code]
  • Travis, thanks for your reply and sorry for my bit emotional post earlier! I was haunted in the last 2 weeks by the strange behavior of the licensing algorithm... Trying to help people fixing their problem and not being able to.
    Jim, my licenses are device-specific, users know that on forehand (although I have in reality a relaxed policy on it).
    Thanks again!
  • Travis,

    In your loop, val starts out 0 and gets assigned as below for each iteration  through the array bytes. Can you tell me what's happening there with " + bytes" with no index specified ?

    val = (val * 997) + bytes;

    Thanks