base32 icon indicating copy to clipboard operation
base32 copied to clipboard

Incrementing $n in the wrong order?

Open deakjahn opened this issue 1 year ago • 3 comments

I don't use your actual PHP code directly but ported it to another language, but it seems to me that

https://github.com/ChristianRiesen/base32/blob/e8b7d85382e396b101d418844b997b4cd744cb8f/src/Base32.php#L104-L105

should be the other way around: first read the character, then increment $n. As it stands now, it will never read the first character of the input string.

Or, in one line:

$val += $chars[$n++];

deakjahn avatar Dec 25 '24 12:12 deakjahn

Just another small idea, doesn't deserve a separate issue:

https://github.com/ChristianRiesen/base32/blob/e8b7d85382e396b101d418844b997b4cd744cb8f/src/Base32.php#L157-L163

I would modify this to:

$bitLen -= 8;
$decoded .= \chr($val >> $bitLen);
$val = $val & ((1 << $bitLen) - 1);

Actually, you could do something similar in the encoding part as well, $shift is similarly without any extra benefit there. Not really important, of course, this won't mean any performance difference these days. :-)

deakjahn avatar Dec 25 '24 12:12 deakjahn

Thanks for the inputs. I agree with the $shift part, that could be changed as it doesn't do anything else here. I think thats a remnant of a refactor that was left over, so thanks for spotting that.

As for the other one, you could combine it into one line, but it would hurt slightly in readability and also the classic ++$n versus $n++ confusion some people get. Here no matter what, the result would be the same. Again, mainly done for readability then anything else.

As for that being a bug, I don't think so, but I'm more then happy to be proven wrong. If it was a bug the library wouldn't pass the test vectors from the official RFC and people who use it, mainly for OTP and some crypto stuff, wouldn't be able to as it would output wrong data. Can you provide a case where it causes an error? Either Input, expected output, received output, or even a full unit test addition that breaks with the current implementation?

ChristianRiesen avatar Dec 26 '24 09:12 ChristianRiesen

Well, as I mentioned, I didn't use it verbatim, I just ported it to Dart. And I test it with the very same vectors, of course, and for me it works with that modification. Even thinking about it, if you consider the first loop, $n will be incremented before you read the first character... How will you ever get the first? The decoding is different, you grab the $string[0] first but not in the encoding.

These are my current versions and they all pass the foobar tests. I modified the shift in both and also modified the writing into an if-else. Apart from slightly different variable names here and there and obvious differences due to the two languages having different features, it's the same except for that single difference of incrementing index after reading, nothing else:

String convert(List<int> input) {
  final padded = [...input, 0, 0, 0, 0, 0];
  final encoded = StringBuffer();

  for (int index = 0, bits = 0, value = 0; index < input.length || bits != 0;) {
    if (bits < 5) {
      value <<= 8;
      bits += 8;
      value += padded[index++];
    }
    if (index - (bits > 8).toInt() > input.length && value == 0) {
      bits -= 5;
      encoded.write('=');
    } else {
      bits -= 5;
      encoded.write(_base32Alphabet[value >> bits]);
      value &= (1 << bits) - 1;
    }
  }

  return encoded.toString();
}
Uint8List convert(String input) {
  final decoded = <int>[];
  if (input.isEmpty) return Uint8List(0);

  int value = _base32Alphabet[input[0]]!;
  for (int index = 0, bits = 5; index < input.length;) {
    if (bits < 8) {
      value <<= 5;
      bits += 5;
      final next = (++index < input.length) ? input[index] : '=';
      if (next == '=') index = input.length;
      value += _base32Alphabet[next]!;
    } else {
      bits -= 8;
      decoded.add(value >> bits);
      value &= (1 << bits) - 1;
    }
  }

  return Uint8List.fromList(decoded);
}

deakjahn avatar Dec 26 '24 11:12 deakjahn