Skip to content

Represent big integers as arrays of bytes #87

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

Merged
merged 15 commits into from
Nov 27, 2024

Conversation

barsnick
Copy link
Contributor

@barsnick barsnick commented Oct 24, 2024

Describe your changes

In PR #65, support for proper coding of large integer (xs:integer) was added, aiding in the proper handling of X509SerialNumber.

Yet the API presented those numbers in the same style as EXI internally, i.e. with 8/7 padding, adding an indicator MSB to each octet for understanding whether the sequence continues.

This change now expects those numbers as arrays of bytes (still within an exi_unsigned_t), representing the integer, without any padding. The byte order is big-endian, i.e. leading bytes in the array have the most significant meaning.

Issue ticket number and link

Relates to issue #54
Amends PR #65

Checklist before requesting a review

  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • I read the contribution documentation and made sure that my changes meet its requirements

@barsnick
Copy link
Contributor Author

barsnick commented Oct 24, 2024

Missing:

  • Separate array sizes (and possibly types) for the raw 8-bit representation and the padded 8/7-bit representation
  • Documentation of this particular API
  • Tests/unit tests

@barsnick barsnick changed the title Represent big integers as array of bytes Represent big integers as arrays of bytes Oct 24, 2024
@barsnick barsnick requested a review from SebaLukas October 24, 2024 13:40
Copy link
Member

@SebaLukas SebaLukas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Maybe I have found one small thing.
But I have not yet generated the code and tested it against the libcbv2g unit tests

@SebaLukas
Copy link
Member

libcbv2g with the generated code builds without problems. Unit tests passed and EVerest SIL work as well. So happy to merge this one 👍

@@ -134,6 +134,24 @@ int exi_basetypes_convert_64_from_signed(const exi_signed_t* exi_signed, int64_t
return res;
}

static void _reverse_array(uint8_t* data, size_t data_size)
{
if (!data || !data_size)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this function is static and you control the inputs, why should it have such a silent error handling of data? It will have gone wrong in exi_basetypes_convert_bytes_from_unsigned before this function is reached.

data_size makes sense of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I was sort of "safe programming".

This code isn't exactly a hot path though.

@@ -134,6 +134,24 @@ int exi_basetypes_convert_64_from_signed(const exi_signed_t* exi_signed, int64_t
return res;
}

static void _reverse_array(uint8_t* data, size_t data_size)
Copy link
Contributor

@SiebrenW SiebrenW Oct 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get why we want to reverse it, but I rather see it written backwards from the get go to speed it up a bit.

Nice to have. I realise this is technically not easy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, EXI internally uses the other direction, from LSB to MSB. I took a "sort of" internal vote on this:

  • MSB to LSB seemed more natural to two people (YMMV though).
  • OpenV2G also does a byte order reversal.

You mean by "backwards from the get" to fill the array in the opposite order, instead of reversing it after the fact. (Speaking for the decoding direction only here, obviously.)

Let me have a look at that. In the decoder, we grow the result array from the inputs. I don't us gaining much from creating a larger array, filling it from the back, and then shrinking it to size.

From the encoder point of view, you may have a point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the encoder point of view, you may have a point.

I just realized, I already did it directly in the encoder. 😊

@SiebrenW
Copy link
Contributor

Another general question then: do you want to change the generated bigint datatype too? You could just use the uint8_t array, a sign and a size struct instead of using the exi_signed thingy for instance. I initially picked the latter out of ease, but do tell what you think is better.

You can mess with alignment and pack the struct a bit more by decreasing the unneeded bits for the size;

struct {
  uint8_t data[20];
  uint8_t size : 7;
  uint8_t sign : 1; 
} SerialNumber;

I will cost some computational overhead though. Probably not worth it.

@barsnick
Copy link
Contributor Author

I initially picked the latter out of ease, but do tell what you think is better.

I like your choice. There's not much to be gained by yet another representation, e.g. your struct SerialNumber.

As I mentioned, the internal size (for plenty of 7/8 octets) and the external size should be different anyway.

@barsnick barsnick marked this pull request as ready for review November 20, 2024 07:51
@barsnick barsnick requested a review from chausGit as a code owner November 20, 2024 07:51
@barsnick barsnick requested review from chausGit and removed request for chausGit November 20, 2024 07:52
Signed-off-by: Moritz Barsnick <[email protected]>
Signed-off-by: Moritz Barsnick <[email protected]>
For code readability.

Signed-off-by: Moritz Barsnick <[email protected]>
When adding the final byte or octet, skip it when its value is zero.
Trailing 0-octets are meaningless in both cases and shouldn't be provided.

Signed-off-by: Moritz Barsnick <[email protected]>
Found by review, confirmed by cppcheck.

Also reorder the code lines to a more logical order.

Signed-off-by: Moritz Barsnick <[email protected]>
Signed-off-by: Moritz Barsnick <[email protected]>
@barsnick barsnick force-pushed the feature/use_big_int_for_integer_fixup branch from c0f3a37 to 8f00adb Compare November 20, 2024 10:47
It had some previously unexpected corner cases:
- It would not always write the correct continuation flag into the final EXI byte.
- It could overflow input bytes, as it always fetched 8 bits from the integer, and
  dumped 7 bits to EXI.

Signed-off-by: Moritz Barsnick <[email protected]>
@barsnick barsnick merged commit 26a748b into main Nov 27, 2024
1 check passed
@barsnick barsnick deleted the feature/use_big_int_for_integer_fixup branch November 27, 2024 07:37
andcaspe pushed a commit to andcaspe/cbexigen that referenced this pull request Dec 5, 2024
* fix minor style issues

Signed-off-by: Moritz Barsnick <[email protected]>

* comment on size decision

Signed-off-by: Moritz Barsnick <[email protected]>

* signed decoder: convert EXI raw 7 bit integer octet array to 8 bit octet array

Signed-off-by: Moritz Barsnick <[email protected]>

* signed encoder: convert 8 bit octet array to EXI raw 7 bit integer octet array

Signed-off-by: Moritz Barsnick <[email protected]>

* fix minor style issues

For code readability.

Signed-off-by: Moritz Barsnick <[email protected]>

* avoid adding zero bytes/octets at the ends of the sequences

When adding the final byte or octet, skip it when its value is zero.
Trailing 0-octets are meaningless in both cases and shouldn't be provided.

Signed-off-by: Moritz Barsnick <[email protected]>

* drop dead code

Found by review, confirmed by cppcheck.

Also reorder the code lines to a more logical order.

Signed-off-by: Moritz Barsnick <[email protected]>

* implement array reversal function

Signed-off-by: Moritz Barsnick <[email protected]>

* reverse the byte orders of the raw large integer byte arrays

Signed-off-by: Moritz Barsnick <[email protected]>

* no need to check for pointer validity in static function

Signed-off-by: Moritz Barsnick <[email protected]>

* exi_basetypes_encoder: use the correct function for large integer conversion

Signed-off-by: Moritz Barsnick <[email protected]>

* exi_basetypes: add comments for large integer conversion functions

Signed-off-by: Moritz Barsnick <[email protected]>

* exi_basetypes: add FIXMEs to exi_basetypes_convert_bytes_to_unsigned()

Signed-off-by: Moritz Barsnick <[email protected]>

* exi_basetypes: properly initialize variable

Signed-off-by: Moritz Barsnick <[email protected]>

* exi_basetypes: rewrite exi_basetypes_convert_bytes_to_unsigned()

It had some previously unexpected corner cases:
- It would not always write the correct continuation flag into the final EXI byte.
- It could overflow input bytes, as it always fetched 8 bits from the integer, and
  dumped 7 bits to EXI.

Signed-off-by: Moritz Barsnick <[email protected]>

---------

Signed-off-by: Moritz Barsnick <[email protected]>
Signed-off-by: andreu.castillo <[email protected]>
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

Successfully merging this pull request may close these issues.

4 participants