Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incrementing $n in the wrong order? #35

Open
deakjahn opened this issue Dec 25, 2024 · 3 comments
Open

Incrementing $n in the wrong order? #35

deakjahn opened this issue Dec 25, 2024 · 3 comments

Comments

@deakjahn
Copy link

deakjahn commented Dec 25, 2024

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

base32/src/Base32.php

Lines 104 to 105 in e8b7d85

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

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
Copy link
Author

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

base32/src/Base32.php

Lines 157 to 163 in e8b7d85

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

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. :-)

@ChristianRiesen
Copy link
Owner

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?

@deakjahn
Copy link
Author

deakjahn commented Dec 26, 2024

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);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants