Decode Slatepack with CyberChef?

As I understand it the first slatepack in SRS without using a receiver address is sent in an unencrypted, encoded, “ASCII Armor”, format.

Does anyone know if they can be decoded in CyberChef then?

https://gchq.github.io/CyberChef/

BEGINSLATEPACK. 8QkaDJf2At2eNhf pn1N2efwaZWFxEe 8mnQ4SpZoMeUgMp 4Q58bbPGo18EMfD P5qRDr15WsdKHmv WnF34PpDifHhftX P4kCX4M7boToPsy C1djGta79dwdKAA AfH1yqPxLeqv4vf ueaETbknrZUcagh jfrVuKJLtirksN8 Lup9spKxcitF4nb 9bcEJ8DXyCWTbw1 YU9CfTCbc7igML3 qTDoEtyom. ENDSLATEPACK.

I don’t know, but i wonder why someone would not want to encrypt the slatepack in step 1. My view was always that you want to have it encrypted, except for maybe some special cases where it might be preferred to not need encryption from one party, eg. donations via RSR. Do you know of any case where it would make sense to not encrypt SRS step1 slatepack?

Yes, maybe offering an unsolicited payment to a friend or posting first reply first serve giveaways on a forum, for casual purposes I think I would use unaddressed SRS more often than any other format.

Using “From Base58 (Bitcoin Alphabet)” seems like maybe the right start.

It does not go to readable ASCII text, but it does go into binary in a sort of organized looking way.

(cutting out begin and end text, using From Base58 and To Binary)

11110011 10111110 11110001 01110111 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 10001011 00000000 00000100 00000000 00000011 01011110 10001011 01000110 00010010 11001010 11100101 01001000 01001111 10101000 11111101 00110001 01001110 00010111 10100110 11001110 10110100 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000110 00000000 00000000 00000000 00000000 00000101 11110101 11100001 00000000 00000000 00000000 00000000 00000000 00000001 01011110 11110011 11000000 00000001 00000000 00000011 11101010 11011110 11100100 01010111 10100101 11111001 01110011 00101100 10010000 10110011 00001001 10111000 01010101 10101110 10111100 11010011 00011001 11100001 01101001 11110011 00001110 10100101 00100001 10110100 00101001 10011111 00110111 11001101 01110100 11001101 01100000 10100110 00000011 11101111 01001001 10010001 00000110 11011011 01001011 00101110 10101001 10101100 10000001 01100111 11000110 10101000 10111010 01101100 11111101 00110101 01001110 00001111 00001000 11010101 00001000 01010011 11111100 11100100 10101100 00000011 11110011 11110101 00011010 10100100 11001001 00000000

I’m not even sure if a slatepack actually converts to human readable data, but I know that some info like sent amount is in there somehow, and I would like to be able to extract it.

From: Slatepack - Grin Documentation

SlatepackMessage armor payloads are encoded similar to legacy bitcoin addresses, with the primary differences being that the SimpleBase58Check used here does not include version bytes and includes the error checking code at the beginning of the payload instead of at the end.

  1. SHA256(SHA256(SLATEPACK_MESSAGE_BINARY))
  2. First four bytes from previous step are ERROR_CHECK_CODE
  3. Concatenate ERROR_CHECK_CODE + SLATEPACK_MESSAGE_BINARY
  4. Base58 encode the output from the previous step to complete the armor Payload

So it seems like this is maybe it, then we cut the first four error check bytes off the binary and we are left with a binary slatepack message:

00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 10001011 00000000 00000100 00000000 00000011 01011110 10001011 01000110 00010010 11001010 11100101 01001000 01001111 10101000 11111101 00110001 01001110 00010111 10100110 11001110 10110100 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000110 00000000 00000000 00000000 00000000 00000101 11110101 11100001 00000000 00000000 00000000 00000000 00000000 00000001 01011110 11110011 11000000 00000001 00000000 00000011 11101010 11011110 11100100 01010111 10100101 11111001 01110011 00101100 10010000 10110011 00001001 10111000 01010101 10101110 10111100 11010011 00011001 11100001 01101001 11110011 00001110 10100101 00100001 10110100 00101001 10011111 00110111 11001101 01110100 11001101 01100000 10100110 00000011 11101111 01001001 10010001 00000110 11011011 01001011 00101110 10101001 10101100 10000001 01100111 11000110 10101000 10111010 01101100 11111101 00110101 01001110 00001111 00001000 11010101 00001000 01010011 11111100 11100100 10101100 00000011 11110011 11110101 00011010 10100100 11001001 00000000

But it is machine readable, not human readable, I would like to know how it’s read and have a decoder eventually.

Grin has 9 zeros right? So I would guess 1 grin is expressed in code as 1,000,000,000 decimal but if not let me know.

The first thing I would like to decode is the amount.

1 Like

Aha! I think I’ve found it. Amount ends at character 746 (including error check code)

The Writeable implementation is how it is encoded into binary and the Readable part is how it is decoded from a binary. All the special encoding/decoding can be found above e.g. for SigsWrapRef or SlateOptFields.

In case you’ll ever need, I think this is how we serialize/deserialize v4 slates grin-wallet/v4.rs at master · mimblewimble/grin-wallet · GitHub

1 Like


101111101011110000100000000 = 100000000 = .1 Grin

1 Like

Field amount is u64 so it’s 8 bytes. The 4 bytes on the left of your highlight are all filled with zeros. The next byte has a value of 00000110. You can guess if that’s the status as defined here grin-wallet/v4_bin.rs at master · mimblewimble/grin-wallet · GitHub
It might be if you have only the amount and fee values.

1 Like

Does that mean we have a transaction limit of 18,446,744,073.709551615 Grin?

Field might have to be expanded for some galaxy real estate deals far in the future… or they’re gonna have to process them in multiple transactions.

Btw, the status field is a bitmask of which fields in SlateOptFields to expect when you read. Your mark of 110 means it will contain amount and fee, so the Readable part first reads status bitmask and from this knows how many bytes to read and what they represent.

Regarding our limits, that’s a good point, I’ve added a hard fork event to my calendar.

1 Like

So fee is 101011110111100111100000 = 23000000 = .023 Grin

1 Like

Bingo. You can even read the slatepack locally with the unpack command to check if that’s correct.

Oh I have the brainpower now this morning to digest this, thank you.

So a slatepack with amt, fee, and feat would have 00001110? Is 0x1110 shorthand for this?

Yes. If you run this in python3 you’ll see

>>> bin(0x02 | 0x04 | 0x08)
'0b1110'

I had to correct the comments above. I wrote as 0x first which is in hexadecimal, but you don’t write bits in this mode. It’s simply just 1110, so no 0x prefix.

1 Like

So is there anything in an unaddressed slatepack that is unique to the sender?

i.e. if two different wallets of identical version both create an unaddressed send .1 grin slatepack, will they create an identical slatepack?

I suspect the answer is no, but it would be interesting if it was yes. There would then be generic transaction starting slatepacks. If it is no, then I am curious what the unique information is that’s involved.

I will test this myself when I get around to loading two wallets.

Oh never mind, even from the same wallet it will produce a different slatepack. Maybe that is because of “lockheight”.

Each slate gets assigned a when it is created UUID which is a part of the slate. We store slate related data that is private to us (some private keys we create to sign the slate later) in a structure called Context. This is also where the wallet remembers the amount associated to a slate.