Calculate a checksum from hex string?

I have a hex string with 23 two-character hex byte representations (so 46 characters long in total).

I need to calculate a simple bitwise checksum (adding each hex byte and discarding the overflow) and add it to the end.

And good guidance on how to do this? A simple for loop iterating over the string probably won’t cut it as it may make the rule execution time too long.

Hi Dave,
If the use case allows it, I would advise using a more common checksum algorithm such as MD5, SHA1, SHA256, etc. They are fast and reliable and usually easy to integrate. Please find a JSR223 Groovy example attached:

import groovy.time.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory

// init logger
Logger log = LoggerFactory.getLogger('GroovyScript')

// test value
String value = '4f70656e48414220697320617765736f6d65'

// start stopwatch
Date startTime= new Date()

// calculate check-sums and log result
log.warn('MD2: {}', value.digest('MD2'))
log.warn('MD5: {}', value.md5())
log.warn('SHA1: {}', value.digest('SHA-1'))
log.warn('SHA256: {}', value.digest('SHA-256'))

// stop stopwatch & log total execution time
TimeDuration duration = TimeCategory.minus(new Date(), startTime)
log.warn('Execution Time: {}', duration)

Result:

2021-01-16 18:17:17.258 [INFO ] [me.core.service.AbstractWatchService] - Loading script 'hash.groovy'
2021-01-16 18:17:17.381 [WARN ] [GroovyScript                        ] - MD2: 821bd7d25f600f94d98058db6ab578bb
2021-01-16 18:17:17.382 [WARN ] [GroovyScript                        ] - MD5: 85dec2c871de462a096594aba51c637a
2021-01-16 18:17:17.383 [WARN ] [GroovyScript                        ] - SHA1: 5428967961bc28567f19f501d3579f4a59de6d30
2021-01-16 18:17:17.384 [WARN ] [GroovyScript                        ] - SHA256: bd94203e730ee01a854eff32d1559e1375a5989b7f390d447d93bf40adc7a2b0
2021-01-16 18:17:17.385 [WARN ] [GroovyScript                        ] - Execution Time: 0.004 seconds

If you really need a custom algorithm, I would still recommend using a JSR223 rule written in JavaScript, Groovy or Python. If I understand your requirement correctly, you should not encounter performance issues.

Using bash:

#!/bin/bash
a="0123456789ABCDEF0123456789ABCDEF01234567ABCDEF"
b=`echo -n $a | sed 's/\(..\)/0x\1 + /g' | sed -e 's/$/0/'`
c=$((0xFF & $b))
printf '%x\n' $c

Is there any way we can modify above logic and calculate one’s complement checksum for hex string.

Thanks,
Rishabh

Like this ?

#!/bin/bash
a="0123456789ABCDEF0123456789ABCDEF01234567ABCDEF"
b=`echo -n $a | sed 's/\(..\)/0x\1 + /g' | sed -e 's/$/0/'`
c=$((0xFF & $b))
d=`printf '%x' $c`
e=`echo $d | tr "0123456789abcdef" "fedcba987654321"`
echo $e

Thanks for the reply :slight_smile:
Actually in may case string is:
a=“85100200007F5D678ACDB2E6CC03537411AE2E95DA120161ECB6C92D5E237C67F0E8FAC29EE1419375B9E17BA6AEB147D994BF14C31D8DB7FB577A5C09767E6CC0D41AB5CF368FC592514F962E8DB171DC08E80C85DE36F690A85D34F842572DA1D246C3EC05AEC3899CE27F8C28BCB9C31191C347DD64E552AF5AFF500E6E6F39E866351D”
and it’s one’s complement checksum value should come “47”.

Regards,
Rishabh

You might have to reveal what language you are working in.

sure ?
I used two online checksum calculators and they state the the 2’s complement would be 0x44
The adapted script shows one’s complement to be 0x43.
2’s complement then is: 0x43 +1 => 0x44.
So I would assume that the modified script would be ok.

For a test of my script and the online checksum calculators I used your hex number.

Have to agree with Wolfgang: The one’s complement 8-bit checksum of the string given here should be 0x43.
An openHAB ECMA-11 javascript (copy this to the UI script editor in OH and press “Run now” while watching the openHAB log) to do the same calculation as Wolfgang’s shell script:

var a="85100200007F5D678ACDB2E6CC03537411AE2E95DA120161ECB6C92D5E237C67F0E8FAC29EE1419375B9E17BA6AEB147D994BF14C31D8DB7FB577A5C09767E6CC0D41AB5CF368FC592514F962E8DB171DC08E80C85DE36F690A85D34F842572DA1D246C3EC05AEC3899CE27F8C28BCB9C31191C347DD64E552AF5AFF500E6E6F39E866351D";
var sum = 0;

// Convert a hex string to bytes and calculate one's complement 8-bit checksum
for (var c = 0; c < a.length; c += 2) {
  byte = parseInt(a.substr(c, 2), 16);
  sum = (sum + byte);
}
sum = ~sum & 255;
console.log("Checksum: 0x" + sum.toString(16));
2 Likes

Thanks to all for reply :slight_smile:
Yes sorry it was typo mistake one’s complement will be 43.
I am writing in bash script.
At below line I am not getting what to write in my string case after ‘tr’.
e=echo $d | tr "*0123456789abcdef*" "*fedcba987654321*"

Regards,
Rishabh

keep the original content that I provided.

$d contains the 8-bit checksum of your original hex number.
tr is being used to build the one’s complement. As the complement is the inverse ( 0 => 1; 1=> 0 ) for each single bit translate ( tr ) can be used to calculate it.
The two arguments describe how tr should do the translation.
Compare the individula positions of both arguments:
0 <=> f
1 <=> e
2 <=> d

Thank you very much. Now its working fine. :slight_smile:

1 Like