Skip to content

Commit b5b005a

Browse files
committed
Commit the changes that let SS58 work with any arbitrary length payload.
Substrates SS58 address format doc prescribes checksum lengths only for payloads of 1, 2, 4, 8, or 32 bytes. For any other payload, the behaviour is undefined. For lack of any other clear guidance beyond the abundance of 2 byte checksums in the actual live use of SS58, this library is implementing a default checksum of 2 bytes for otherwise undefined payload lengths. This change adds a `Base58::SS58.encode` and a `Base58::SS58.decode` method for dealing with arbitrary data, of arbitrary sizes.
1 parent 00c7cb6 commit b5b005a

File tree

3 files changed

+32
-15
lines changed

3 files changed

+32
-15
lines changed

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.0
1+
0.2.1

shard.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: base58
2-
version: 0.2.0
2+
version: 0.2.1
33

44
authors:
55
- Kirk Haines <[email protected]>

src/base58/ss58.cr

+30-13
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ module Base58
6262

6363
# :nodoc:
6464
def self.check_args(address, format)
65-
if format < 0 || format > 16383 || format == 46 || format == 47
66-
raise ArgumentError.new("Invalid address format: #{format}")
67-
end
68-
6965
address_size = address.size
7066
if TwoByteChecksumAddresses.includes?(address_size)
7167
checksum_length = 2
@@ -75,20 +71,36 @@ module Base58
7571
raise ArgumentError.new("Invalid address size: #{address_size}; Substrate addresses can only be 1, 2, 4, 8, 32, or 33 bytes long")
7672
end
7773

74+
{
75+
type: Base58::Checksum::SS58,
76+
prefix: String.new(derive_format(format)),
77+
checksum_length: checksum_length,
78+
checksum_prefix: ChecksumPrefix,
79+
}
80+
end
81+
82+
# :nodoc:
83+
def self.derive_format(format)
84+
if format < 0 || format > 16383 || format == 46 || format == 47
85+
raise ArgumentError.new("Invalid address format: #{format}")
86+
end
87+
7888
if format < 64
79-
format_bytes = Slice[format.to_u8]
89+
Slice[format.to_u8]
8090
else
81-
format_bytes = Slice[
91+
Slice[
8292
(((format & 0b0000_000011111100) >> 2) | 0b01000000).to_u8,
8393
((format >> 8) | ((format & 0b0000000000000011) << 6)).to_u8,
8494
]
8595
end
86-
{
87-
type: Base58::Checksum::SS58,
88-
prefix: String.new(format_bytes),
89-
checksum_length: checksum_length,
90-
checksum_prefix: ChecksumPrefix,
91-
}
96+
end
97+
98+
# To encode content with an arbitrary length payload, use the `encode` method instead
99+
# of `encode_address`. The Substrate SS58 spec only prescribes checksum lengths for
100+
# payloads which are 1, 2, 4, 8, or 32 bytes long. So, for other payloads, this library
101+
# is defaulting to a 2 byte checksum.
102+
def self.encode(payload, into, format : Int = 42)
103+
Base58.encode(payload, into: into, check: Check.new(type: Base58::Checksum::SS58, prefix: String.new(derive_format(format)), checksum_length: checksum_length(payload), checksum_prefix: ChecksumPrefix))
92104
end
93105

94106
def self.encode_address(address, into : String.class = String, format : Int = 42)
@@ -147,6 +159,11 @@ module Base58
147159
Base58.encode(address, into: into, check: Check.new(**check_args(address, format)))
148160
end
149161

162+
# To decode content with an arbitrary length payload, use `decode` instead of `decode_address`.
163+
def self.decode(payload, into, format = 42)
164+
decode_address(payload, into: into, format: format)
165+
end
166+
150167
def self.decode_address(address, into : String.class = String, format : Int? = nil)
151168
String.new(decode_address(address, Slice(UInt8), format))
152169
end
@@ -278,7 +295,7 @@ module Base58
278295
when 17
279296
8
280297
else
281-
0
298+
2
282299
end
283300
end
284301

0 commit comments

Comments
 (0)