Skip to content

Instantly share code, notes, and snippets.

@rambo
Created January 17, 2025 12:05
Show Gist options
  • Save rambo/018b55fb82dad66ac8a8188b2b7c59d1 to your computer and use it in GitHub Desktop.
Save rambo/018b55fb82dad66ac8a8188b2b7c59d1 to your computer and use it in GitHub Desktop.
"""
Hash the STM32 UID, Python version
Original C code from from https://pcbartists.com/firmware/stm32-firmware/generating-32-bit-stm32-unique-id/
"""
import pyb
import struct
# Magic numbers for 32-bit hashing, copied from Murmur3
C1 = 0xcc9e2d51
C2 = 0x1b873593
def fetch32(packed: bytes) -> int:
"""Fetches aval 32-bit value."""
return struct.unpack('<L', packed)[0]
def rotate32(val: int, shift: int) -> int:
"""Rotates aval 32-bit integer left or right by 'shift' positions."""
if shift == 0:
return val
return (val >> shift) | (val << (32 - shift)) & 0xFFFFFFFF
def fmix(hme: int) -> int:
"""A 32-bit to 32-bit integer hash copied from Murmur3."""
hme = (hme ^ (hme >> 16)) & 0xFFFFFFFF
hme = (hme * 0x85ebca6b) & 0xFFFFFFFF
hme = (hme ^ (hme >> 13)) & 0xFFFFFFFF
hme = (hme * 0xc2b2ae35) & 0xFFFFFFFF
return (hme ^ (hme >> 16)) & 0xFFFFFFFF
def mur(aval, bval) -> int:
"""Helper from Murmur3 for combining two 32-bit values."""
aval = (aval * C1) & 0xFFFFFFFF
aval = rotate32(aval, 17)
aval = (aval * C2) & 0xFFFFFFFF
bval = (bval ^ aval) & 0xFFFFFFFF
bval = rotate32(bval, 19)
return (bval * 5 + 0xe6546b64) & 0xFFFFFFFF
def hash32_len_5_to_12(s: bytes, len_hash: int = 12):
"""Computes the hash for strings of length 5 to 12 using Murmur3-like hash."""
aval = len_hash
bval = aval * 5
cval = 9
dval = bval
aval += fetch32(s[0:4])
bval += fetch32(s[len_hash - 4:])
cval += fetch32(s[(len_hash >> 1) & 4:])
return fmix(mur(cval, mur(bval, mur(aval, dval))))
def get_unique_id_str() -> str:
"""Get unique ID like we did in the C code"""
full_id = pyb.unique_id()
# Reorder the words in the ID
w0 = struct.unpack('<L', full_id[0:4])[0]
w1 = struct.unpack('<L', full_id[4:8])[0]
w2 = struct.unpack('<L', full_id[8:12])[0]
word_reorder = struct.pack('<L', w2) + struct.pack('<L', w1) + struct.pack('<L', w0)
# Hash the reordered id
hashed = hash32_len_5_to_12(word_reorder)
# Return as hex
return "{:08X}".format(hashed)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment