RLP編碼和解碼

2021-08-11 06:58:22 字數 4864 閱讀 2633

github上英文介紹(解碼部分為本人所編輯):

rlp(recursive length prefix,遞迴的長度字首)是一種編碼規則,可用於編碼任意巢狀的二進位制陣列資料。rlp編碼的結果也是二進位制序列。rlp主要用來序列化/反序列化資料。

目錄

rlp編碼的定義只處理以下2類底層資料:

所有上層型別的資料需要轉成以上的2類資料,才能進行rlp編碼。轉換的規則rlp編碼不統一規定,可以自定義轉換規則。例如struct可以轉成列表;int可以轉成二進位制序列(屬於字串這一類, 必須去掉首部0,必須用大端模式表示);map型別可以轉換為由k和v組成的結構體、k按字典順序排列的列表:[[k1,v1],[k2,v2]…] 等。

從上面的資料型別定義中可以看出,rlp編碼的資料是可巢狀的。從rlp編碼的名字可以看出,rlp編碼是遞迴的,這一點從下面的規則和**可以看出。

rlp編碼的重點是給原始資料前面新增若干位元組的字首,而且這個字首是和資料的長度相關的,並且是遞迴的。

rlp編碼中的長度是資料的實際儲存空間的位元組大小,去掉首位0的正整數,用大端模式表示的二進位制格式表示。

rlp編碼規定資料(字串或列表)的長度的長度不得大於8位元組。因為超過8位元組後,乙個位元組的字首就不能儲存了。

如果字串的長度是1個位元組,並且它的值在[0x00, 0x7f] 範圍之間,那麼其rlp編碼就是字串本身。即字首為空,用字首代表字串本身;

否則,如果乙個字串的長度是0-55位元組,其rlp編碼是字首跟上(拼接)字串本身,字首的值是0x80加上字串的長度。由於在該規則下,字串的最大長度是55,因此字首的最大值是0x80+55=0xb7,所以在本規則下字首(第乙個位元組)的取值範圍是[0x80, 0xb7];

如果字串的長度大於55個位元組,其rlp編碼是字首跟上字串的長度再跟上字串本身。字首的值是0xb7加上字串長度的二進位制形式的位元組長度(即字串長度的儲存長度)。即用額外的空間儲存字串的長度,而字首中只存字串的長度的長度。例如乙個長度是1024的字串,字串長度的二進位制形式是\x04\x00,因此字串長度的長度是2個位元組,所以字首應該是0xb7+2=0xb9,由此得到該字串的rlp編碼是\xb9\x04\x00再跟上字串本身。因為字串長度的長度最少需要1個位元組儲存,因此字首的最小值是0xb7+1=0xb8;又由於長度的最大值是8個位元組,因此字首的最大值是0xb7+8=0xbf,因此在本規則下字首的取值範圍是[0xb8, 0xbf];

以上3個規則是針對字串的,接下來的兩個規則針對列表的。由於列表的任意巢狀的,因此列表的編碼是遞迴的,先編碼最裡層列表,再逐步往外層列表編碼。如果乙個列表的總長度(payload,列表的所有項經過編碼後拼接在一起的位元組大小)是0-55位元組,其rlp編碼是字首依次跟上列表中各項的rlp編碼。字首的值是0xc0加上列表的總長度。在本規則下字首的取值範圍是[0xc0, 0xf7]。本規則與規則2類似;

如果乙個列表的總長度大於55位元組,它的rlp編碼是字首跟上列表的長度再依次跟上列表中各元素項的rlp編碼。字首的值是0xf7加上列表總長度的長度。編碼的第乙個位元組的取值範圍是[0xf8, 0xff]。本規則與規則3類似;

**如下:

def

rlp_encode

(input):

if isinstance(input,str):

if len(input) == 1

and ord(input) <= 0x7f: return input

else: return encode_length(len(input), 0x80) + input

elif isinstance(input,list):

output = ''

for item in input: output += rlp_encode(item)

return encode_length(len(output), 0xc0) + output

defencode_length

(l,offset):

if l < 56:

return chr(l + offset)

elif l < 256**8:

bl = to_binary(l)

return chr(len(bl) + offset + 55) + bl

else:

raise exception("input too long")

defto_binary

(x):

if x == 0:

return

''else:

return to_binary(int(x / 256)) + chr(x % 256)

根據rlp編碼規則和過程,rlp解碼的輸入一律視為二進位制字元陣列,其過程如下:

根據輸入首位元組資料,解碼資料型別、實際資料長度和位置;

根據型別和實際資料,解碼不同型別的資料;

繼續解碼剩餘的資料;

其中,解碼資料型別、實際資料型別和位置的規則如下:

如果首位元組(prefix)的值在[0x00, 0x7f]範圍之間,那麼該資料是字串,且字串就是首位元組本身;

如果首位元組的值在[0x80, 0xb7]範圍之間,那麼該資料是字串,且字串的長度等於首位元組減去0x80,且字串位於首位元組之後;

如果首位元組的值在[0xb8, 0xbf]範圍之間,那麼該資料是字串,且字串的長度的位元組長度等於首位元組減去0xb7,資料的長度位於首位元組之後,且字串位於資料的長度之後;

如果首位元組的值在[0xc0, 0xf7]範圍之間,那麼該資料是列表,在這種情況下,需要對列表各項的資料進行遞迴解碼。列表的總長度(列表各項編碼後的長度之和)等於首位元組減去0xc0,且列表各項位於首位元組之後;

如果首位元組的值在[0xf8, 0xff]範圍之間,那麼該資料為列表,列表的總長度的位元組長度等於首位元組減去0xf7,列表的總長度位於首位元組之後,且列表各項位於列表的總長度之後;

**如下:

def

rlp_decode

(input):

if len(input) == 0:

return

output = ''

(offset, datalen, type) = decode_length(input)

if type is str:

output = instantiate_str(substr(input, offset, datalen))

elif type is list:

output = instantiate_list(substr(input, offset, datalen))

output + rlp_decode(substr(input, offset + datalen))

return output

defdecode_length

(input):

length = len(input)

if length == 0:

raise exception("input is null")

prefix = ord(input[0])

if prefix <= 0x7f:

return (0, 1, str)

elif prefix <= 0xb7

and length > prefix - 0x80:

strlen = prefix - 0x80

return (1, strlen, str)

elif prefix <= 0xbf

and length > prefix - 0xb7

and length > prefix - 0xb7 + to_integer(substr(input, 1, prefix - 0xb7)):

lenofstrlen = prefix - 0xb7

strlen = to_integer(substr(input, 1, lenofstrlen))

return (1 + lenofstrlen, strlen, str)

elif prefix <= 0xf7

and length > prefix - 0xc0:

listlen = prefix - 0xc0;

return (1, listlen, list)

elif prefix <= 0xff

and length > prefix - 0xf7

and length > prefix - 0xf7 + to_integer(substr(input, 1, prefix - 0xf7)):

lenoflistlen = prefix - 0xf7

listlen = to_integer(substr(input, 1, lenoflistlen))

return (1 + lenoflistlen, listlen, list)

else:

raise exception("input don't conform rlp encoding form")

defto_integer

(b)length = len

(b)if

length == 0:

raise exception("input is null")

elif length == 1:

return ord(b[0])

else:

return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256

與其他序列化方法相比,rlp編碼的優點在於使用了靈活的長度字首來表示資料的實際長度,並且使用遞迴的方式能編碼相當大的資料。

當接收或者解碼經過rlp編碼後的資料時,根據第1個位元組就能推斷資料的型別、大概長度和資料本身等資訊。而其他的序列化方法, 不能根據第1個位元組獲得如此多的資訊量。

編碼和解碼

str是以位元組表示的文字,unicode是以字元表示的文字。您可以將文字從位元組解碼為unicode,並使用某種編碼將unicode編碼為位元組。即 str str unicode str encode 編碼,程式設計不可識別的unicode decode 解碼,恢復成字串和中文等def test...

編碼和解碼

1 編碼 encode 編碼方式 拿到明文編碼後對應的位元組 ascii 碼 不支援中文,支援英文 數字 字母 符號 gbk 國標 支援中文 支援英文 數字 字母 符號 英文用16位 中文用16位 unicode 萬國碼 支中文 英文 數字 字母 英文32位 中文32位 utf 8 長度可變的萬國碼...

編碼和解碼

ascii碼 不支援中文,支援英文,數字,符號,使用乙個位元組 8位 來表示 gbk碼 國標碼,支援中文,英文,數字,符號.中文 16位 兩個位元組 英文 16位 兩個位元組 unicode 萬國碼,支援中文,英文,數字,符號 中文 32位 四個位元組 英文 32位 四個位元組 utf 8 長度可變...