parent
df42c99bc9
commit
9b78dd107b
@ -0,0 +1 @@
|
||||
Drop simple-rlp dependency and use internal copy
|
@ -0,0 +1,55 @@
|
||||
# inspired by core/src/trezor/crypto/rlp.py
|
||||
|
||||
import typing as t
|
||||
from collections.abc import Sequence
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
RLPItem = t.Union[t.Sequence["RLPItem"], bytes, int]
|
||||
|
||||
|
||||
def _byte_size(x: int) -> int:
|
||||
if x < 0:
|
||||
raise ValueError("only unsigned ints are supported")
|
||||
return (x.bit_length() + 7) // 8
|
||||
|
||||
|
||||
def _int_to_bytes(n: int) -> bytes:
|
||||
"""Convert to a correctly sized bytes object."""
|
||||
return n.to_bytes(_byte_size(n), "big")
|
||||
|
||||
|
||||
def _encode_with_length(value: bytes, header_byte: int) -> bytes:
|
||||
length = len(value)
|
||||
if length == 1 and value[0] <= 0x7F:
|
||||
return value
|
||||
elif length <= 55:
|
||||
return (header_byte + length).to_bytes(1, "big") + value
|
||||
else:
|
||||
encoded_length = _int_to_bytes(length)
|
||||
return (
|
||||
(header_byte + 55 + len(encoded_length)).to_bytes(1, "big")
|
||||
+ encoded_length
|
||||
+ value
|
||||
)
|
||||
|
||||
|
||||
def encode(value: "RLPItem") -> bytes:
|
||||
"""Encode lists or objects to bytes."""
|
||||
if isinstance(value, int):
|
||||
# ints are stored as byte strings
|
||||
value = _int_to_bytes(value)
|
||||
|
||||
# sanity check: `str` is a Sequence so it would be incorrectly
|
||||
# picked up by the Sequence branch below
|
||||
assert not isinstance(value, str)
|
||||
|
||||
# check for bytes type first, because bytes is a Sequence too
|
||||
if isinstance(value, bytes):
|
||||
header_byte = 0x80
|
||||
elif isinstance(value, Sequence):
|
||||
header_byte = 0xC0
|
||||
value = b"".join(encode(item) for item in value)
|
||||
else:
|
||||
raise TypeError("Unsupported type")
|
||||
|
||||
return _encode_with_length(value, header_byte)
|
@ -0,0 +1,33 @@
|
||||
import pytest
|
||||
|
||||
from trezorlib import _rlp
|
||||
|
||||
VECTORS = ( # data, expected
|
||||
(b"\x10", b"\x10"),
|
||||
(b"dog", b"\x83dog"),
|
||||
(b"A" * 55, b"\xb7" + b"A" * 55),
|
||||
(b"A" * 56, b"\xb8\x38" + b"A" * 56),
|
||||
(b"A" * 1024, b"\xb9\x04\x00" + b"A" * 1024),
|
||||
([b"dog", b"cat", [b"spy"]], b"\xcd\x83dog\x83cat\xc4\x83spy"),
|
||||
([b"A" * 1024], b"\xf9\x04\x03\xb9\x04\x00" + b"A" * 1024),
|
||||
([], b"\xc0"),
|
||||
([b"A"] * 55, b"\xf7" + b"A" * 55),
|
||||
([b"A"] * 56, b"\xf8\x38" + b"A" * 56),
|
||||
([b"A"] * 1024, b"\xf9\x04\x00" + b"A" * 1024),
|
||||
([b"dog"] * 1024, b"\xf9\x10\x00" + b"\x83dog" * 1024),
|
||||
(b"", b"\x80"),
|
||||
(1, b"\x01"),
|
||||
(0x7F, b"\x7f"),
|
||||
(0x80, b"\x81\x80"),
|
||||
(0x1_0000_0001, b"\x85\x01\x00\x00\x00\x01"),
|
||||
(2 ** (54 * 8), b"\xb7\x01" + b"\x00" * 54),
|
||||
(2 ** (55 * 8), b"\xb8\x38\x01" + b"\x00" * 55),
|
||||
([0x1234, 0x5678], b"\xc6\x82\x12\x34\x82\x56\x78"),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data, expected", VECTORS)
|
||||
def test_encode(data: "_rlp.RLPItem", expected: bytes):
|
||||
actual = _rlp.encode(data)
|
||||
assert len(actual) == len(expected)
|
||||
assert actual == expected
|
Loading…
Reference in new issue