7

I've heard that one byte contains as much data as "about 5 trits". However, I'm not entirely clear on how the conversion works.

How do I convert binary data into balanced ternary (and vice versa)?

In particular, I am asking because I'd like to implement proper bytes <-> trytes conversion in PyOTA, but I don't understand how to handle edge cases (especially surrounding the "about 5 trits" part).

mihi
  • 7,324
  • 2
  • 15
  • 34
todofixthis
  • 1,320
  • 8
  • 23
  • mobilefish on youtube has some really great videos about the conversions – GusGorman402 Dec 09 '17 at 22:57
  • That's a very good question. I do not understand the reason for negative vote. Who voted negative. Could you give more details of your vote? – Avelino Dec 10 '17 at 18:11
  • I’m voting to close this question because it is about the legacy-network and it is a good idea to keep only Shimmer/ShimmerEVM and latest IOTA Chrysalis questions – Antonio Nardella Apr 24 '23 at 14:06

1 Answers1

7

There are several ways to convert bytes to trytes, caused by the fact that you can take a different number of bytes at once to convert (the more bytes you take, the less space is wasted).

In theory, you will need log 256 / log 3 = 5.047438028571 trits for each byte.

bytes as starting point

The implementation in ascii2trytes uses 1 byte and converts it to 2 trytes (6 trits), by dividing the byte value by 27 and using the remainder as first tryte and the division result as second tryte.

Then represent these trytes in balanced ternary (0 = 000, 1 = 00+, 2=0+- 3=0+0, 4=0++, 5=+--, etc.) if you really want trits :)

That way, every byte can be converted to trytes, but not every combination of trytes can be converted to bytes. One byte will use 6 trits.

This method is used to encode binary data (like small files) into a transaction message/signature.

trytes as starting point

You can also start with trytes (this method is used to send a transaction - which consists of trytes - via UDP to the neighbors). In this case, create groups of 5 trits (if you have trytes, take every group of consecutive 5 trytes and make 3 groups of 5 trits from it), then encode them to a number from 0 to 242, and put them into a byte.

That way, every tryte combination can be converted to bytes, but there are some byte results (243 to 255) that are never achieved.

bignum arithmetic

In case your language supports it, you can also use bignum arithmetic to convert an arbitrary number of bytes at once to trytes and vice versa. Just multiply by 256 or 27 and add the next tryte/byte. When you are finished (and have a really big number), divide by the other value (27 or 256) and thereby split the values apart. Note that when doing so, leading zero bytes (or trytes) may get lost during roundtrip conversion, so if that is an issue, add a byte (or tryte) with value 1 at the beginning (and strip it off after finishing the convesion back).

This method is essentially the same as you use when trying to output a huge binary number in decimal. While it works, I don't know any practical need in iota applications (since either you have trytes you need to transport-encode as bytes, or bytes you need to transport-encode as trytes, and the other two methods are fine for that).

mihi
  • 7,324
  • 2
  • 15
  • 34
  • Thanks mihi! I must confess, I have an agenda behind asking this question (: Currently, PyOTA does use the ascii2trytes codec, but a number of users have been asking for a more... maths-y conversion process. I've updated my question with more info. – todofixthis Dec 09 '17 at 22:31
  • I hope I have updated the answer accordingly. – mihi Dec 09 '17 at 23:57
  • Thanks! I need to spend some time digesting this. I think an example would help me to understand better, but I think what you've posted so far will definitely help me figure this out! – todofixthis Dec 10 '17 at 02:21
  • Hey @mihi I'm still trying to digest all of this. For the "trytes as a starting point" method, would it make sense to work with groups of 6 trits at a time, instead of 5? This way we could support all possible byte values, and it should also make it possible to decode values encoded using the "bytes as a starting point" method; am I thinking about this the right way? – todofixthis Dec 28 '17 at 19:04
  • when you start with 6 trits, the answer will not fit into a byte in all cases... So you can support all possible byte values, but the idea of starting with trytes is to support all possible tryte values, which you lose when you use 6 trits. – mihi Dec 28 '17 at 19:47
  • 1
    Hm. Ok, I see what you mean there; that makes sense. Maybe the part that I'm grappling with then, is how to design a codec such that to_bytes(to_trits(bytes_value)) == bytes_value (and mutatis mutandis), even when bytes_value contains bytes in the [244,255] range. – todofixthis Dec 30 '17 at 22:31
  • Your requirement is impossible when you add the constraint that every n-byte combination has to result in the same number m of trits, and vice versa. If you skip that constraint, it is possible (e.g. using bignums), but not really feasible. – mihi Dec 31 '17 at 21:48
  • @mihi. For "trytes as a starting point" it is true that 5 trits can represent 243 different values but the range is [-121, 121] and not [0, 255]. Is -121 mapped to 1, -120 to 2 and so on? Or what? – blockmined Jan 21 '18 at 16:41
  • @RobertoGiorgetti Your decision. Either you map -121 to 0, and so on up to 121 to 242, or you map only the negative values (-121 to 122, -120 to 123 and so on up to -1 to 242), like it is done when sign extending a two's complement binary number. – mihi Jan 21 '18 at 21:15
  • @mihi But which are the conversion rules adopted inside iri and wallet codes? I mean the conversion rules adopted during the process of building the bundle. – blockmined Jan 22 '18 at 17:26