Great, looks like base32 Google Authenticator is working with/without space padding, but a few cases remain:

Quote
digits=10:

//var -s %count 7184224 , %key abcdefghijklmnopqrstuvwxyz234567 | echo -a $hotp(%key,%count,sha1,6) vs $hotp(%key,%count,sha1,9) vs $hotp(%key,%count,sha1,10)

result: 421874 vs 147421874 vs 0737356466
the 10 digits value should be 2147421874

It looks like the truncate31bit is being held in a uint32 which overflowed from division by 10^10, as the result here is $calc( 2147421874 % (10^10 % 2^32 ) )

Probably the simplest way to handle it is like:

truncate31bit = math
if (digits < 10) truncate31bit = truncate31 % 10^digits

Quote
timestep > max

//var %ctime 1234567890 | echo -a $totp(key,%ctime,sha1,6,$calc( 3600*48 )) vs $totp(key,%ctime,sha1,6,$calc( 30 )) vs $totp(key,%ctime,sha1,6,$calc( 3600*48 +1))

result: 904921 vs 336986 vs 336986
should be 904921 vs 336986 vs invalid parm

Defaults are for when a parameter is not used, and just like $hotp(key,0,foobar,11) reject the hashname and digits if not within the accepted range, timestep outside 1-172800 should be an error instead of replacing with 30

Quote
Stripping 0x00 bytes from hex keys

It appears that hex keys are no longer encoding bytes 128-255 as UTF8 text, but are still stripping 0x00 bytes. The example below generates identical %base32 and %hexhex results when the bytes are encoded as either hex or base32, and results match the totp.danhersam.com online template. However if changing 1-or-more of the 1st 19 bytes to 0, the base32 encoding continues to match the template, but %hexhex instead matches the %stripd key where the 0x00 are moved to the tail.

Fixing the handling of bytes 128-255 made 13/14 of random 160-bit hex keys be compatible, but having keys with 0's in different locations being treated as equivalent means that it's something less than 2^160 possible keys, as well as not having compatible results for 1/14th of 160-bit keys.

Code
alias totp_hex_zeroes {
  bset &v 1 195 169 233 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
  var -s %hexhex $regsubex($bvar(&v,1-),/(\d+)/g,$base(\t,10,16,2)) , %stripd $remtok(%hexhex,00,0,32)
  while ($numtok(%stripd,32) < 20) var %stripd %stripd 00 | noop $encode(&v,ba)
  var %base32 $remove($bvar(&v,1-).text,=)
  echo -a base32 $totp(%base32) %base32
  echo -a hexhex $totp(%hexhex) %hexhex
  echo -a stripd $totp(%stripd) %stripd
}