Skip to content

Commit ac317c3

Browse files
Stebalienraulk
andauthored
feat: implement f4 addressing (#35)
Co-authored-by: Raúl Kripalani <[email protected]>
1 parent 62a95f3 commit ac317c3

File tree

3 files changed

+190
-138
lines changed

3 files changed

+190
-138
lines changed

address.go

Lines changed: 116 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"math"
99
"strconv"
10+
"strings"
1011

1112
cbor "github.com/ipfs/go-ipld-cbor"
1213
"github.com/minio/blake2b-simd"
@@ -69,6 +70,8 @@ const (
6970
Actor
7071
// BLS represents the address BLS protocol.
7172
BLS
73+
// Delegated represents the delegated (f4) address protocol.
74+
Delegated
7275

7376
Unknown = Protocol(255)
7477
)
@@ -177,6 +180,19 @@ func NewBLSAddress(pubkey []byte) (Address, error) {
177180
return newAddress(BLS, pubkey)
178181
}
179182

183+
// NewDelegatedAddress returns an address using the Delegated protocol.
184+
func NewDelegatedAddress(namespace uint64, subaddr []byte) (Address, error) {
185+
if namespace > math.MaxInt64 {
186+
return Undef, xerrors.New("namespace must be less than 2^63")
187+
}
188+
if len(subaddr) > MaxSubaddressLen {
189+
return Undef, ErrInvalidLength
190+
}
191+
192+
payload := append(varint.ToUvarint(namespace), subaddr...)
193+
return newAddress(Delegated, payload)
194+
}
195+
180196
// NewFromString returns the address represented by the string `addr`.
181197
func NewFromString(addr string) (Address, error) {
182198
return decode(addr)
@@ -209,8 +225,9 @@ func addressHash(ingest []byte) []byte {
209225
}
210226

211227
// FIXME: This needs to be unified with the logic of `decode` (which would
212-
// handle the initial verification of the checksum separately), both are doing
213-
// the exact same length checks.
228+
//
229+
// handle the initial verification of the checksum separately), both are doing
230+
// the exact same length checks.
214231
func newAddress(protocol Protocol, payload []byte) (Address, error) {
215232
switch protocol {
216233
case ID:
@@ -233,6 +250,17 @@ func newAddress(protocol Protocol, payload []byte) (Address, error) {
233250
if len(payload) != BlsPublicKeyBytes {
234251
return Undef, ErrInvalidLength
235252
}
253+
case Delegated:
254+
namespace, n, err := varint.FromUvarint(payload)
255+
if err != nil {
256+
return Undef, xerrors.Errorf("could not decode delegated address namespace: %v: %w", err, ErrInvalidPayload)
257+
}
258+
if namespace > math.MaxInt64 {
259+
return Undef, xerrors.Errorf("namespace id must be less than 2^63: %w", ErrInvalidPayload)
260+
}
261+
if len(payload)-n > MaxSubaddressLen {
262+
return Undef, ErrInvalidLength
263+
}
236264
default:
237265
return Undef, ErrUnknownProtocol
238266
}
@@ -259,17 +287,33 @@ func encode(network Network, addr Address) (string, error) {
259287
return UndefAddressString, ErrUnknownNetwork
260288
}
261289

290+
protocol := addr.Protocol()
291+
payload := addr.Payload()
262292
var strAddr string
263-
switch addr.Protocol() {
264-
case SECP256K1, Actor, BLS:
265-
cksm := Checksum(append([]byte{addr.Protocol()}, addr.Payload()...))
266-
strAddr = ntwk + fmt.Sprintf("%d", addr.Protocol()) + AddressEncoding.WithPadding(-1).EncodeToString(append(addr.Payload(), cksm[:]...))
293+
switch protocol {
294+
case SECP256K1, Actor, BLS, Delegated:
295+
// The checksum and prefix is the same for all protocols
296+
cksm := Checksum(append([]byte{protocol}, payload...))
297+
strAddr = ntwk + fmt.Sprintf("%d", protocol)
298+
299+
// if delegated, we need to write the namespace out separately.
300+
if protocol == Delegated {
301+
namespace, n, err := varint.FromUvarint(payload)
302+
if err != nil {
303+
return UndefAddressString, xerrors.Errorf("could not decode delegated address namespace: %w", err)
304+
}
305+
payload = payload[n:]
306+
strAddr += fmt.Sprintf("%df", namespace)
307+
}
308+
309+
// Then encode the payload (or the rest of it) and the checksum.
310+
strAddr += AddressEncoding.WithPadding(-1).EncodeToString(append(payload, cksm[:]...))
267311
case ID:
268-
i, n, err := varint.FromUvarint(addr.Payload())
312+
i, n, err := varint.FromUvarint(payload)
269313
if err != nil {
270314
return UndefAddressString, xerrors.Errorf("could not decode varint: %w", err)
271315
}
272-
if n != len(addr.Payload()) {
316+
if n != len(payload) {
273317
return UndefAddressString, xerrors.Errorf("payload contains additional bytes")
274318
}
275319
strAddr = fmt.Sprintf("%s%d%d", ntwk, addr.Protocol(), i)
@@ -279,6 +323,19 @@ func encode(network Network, addr Address) (string, error) {
279323
return strAddr, nil
280324
}
281325

326+
func base32decode(s string) ([]byte, error) {
327+
decoded, err := AddressEncoding.WithPadding(-1).DecodeString(s)
328+
if err != nil {
329+
return nil, err
330+
}
331+
332+
reencoded := AddressEncoding.WithPadding(-1).EncodeToString(decoded)
333+
if reencoded != s {
334+
return nil, ErrInvalidEncoding
335+
}
336+
return decoded, nil
337+
}
338+
282339
func decode(a string) (Address, error) {
283340
if len(a) == 0 {
284341
return Undef, nil
@@ -304,6 +361,8 @@ func decode(a string) (Address, error) {
304361
protocol = Actor
305362
case '3':
306363
protocol = BLS
364+
case '4':
365+
protocol = Delegated
307366
default:
308367
return Undef, ErrUnknownProtocol
309368
}
@@ -320,36 +379,65 @@ func decode(a string) (Address, error) {
320379
return newAddress(protocol, varint.ToUvarint(id))
321380
}
322381

323-
payloadcksm, err := AddressEncoding.WithPadding(-1).DecodeString(raw)
324-
if err != nil {
325-
return Undef, err
326-
}
327-
328-
reencodedRaw := AddressEncoding.WithPadding(-1).EncodeToString(payloadcksm)
329-
if reencodedRaw != raw {
330-
return Undef, ErrInvalidEncoding
331-
}
382+
var cksum, payload []byte
383+
if protocol == Delegated {
384+
parts := strings.SplitN(raw, "f", 2)
385+
if len(parts) != 2 {
386+
return Undef, ErrInvalidPayload
387+
}
388+
namespaceStr := parts[0]
389+
subaddrStr := parts[1]
332390

333-
if len(payloadcksm) < ChecksumHashLength {
334-
return Undef, ErrInvalidLength
335-
}
391+
if len(namespaceStr) > MaxInt64StringLength {
392+
return Undef, ErrInvalidLength
393+
}
394+
namespace, err := strconv.ParseUint(namespaceStr, 10, 63)
395+
if err != nil {
396+
return Undef, ErrInvalidPayload
397+
}
336398

337-
payload := payloadcksm[:len(payloadcksm)-ChecksumHashLength]
338-
cksm := payloadcksm[len(payloadcksm)-ChecksumHashLength:]
399+
subaddrcksm, err := base32decode(subaddrStr)
400+
if err != nil {
401+
return Undef, err
402+
}
339403

340-
if protocol == SECP256K1 || protocol == Actor {
341-
if len(payload) != PayloadHashLength {
404+
if len(subaddrcksm) < ChecksumHashLength {
405+
return Undef, ErrInvalidLength
406+
}
407+
subaddr := subaddrcksm[:len(subaddrcksm)-ChecksumHashLength]
408+
cksum = subaddrcksm[len(subaddrcksm)-ChecksumHashLength:]
409+
if len(subaddr) > MaxSubaddressLen {
342410
return Undef, ErrInvalidLength
343411
}
344-
}
345412

346-
if protocol == BLS {
347-
if len(payload) != BlsPublicKeyBytes {
413+
payload = append(varint.ToUvarint(namespace), subaddr...)
414+
} else {
415+
payloadcksm, err := base32decode(raw)
416+
if err != nil {
417+
return Undef, err
418+
}
419+
420+
if len(payloadcksm) < ChecksumHashLength {
348421
return Undef, ErrInvalidLength
349422
}
423+
424+
payload = payloadcksm[:len(payloadcksm)-ChecksumHashLength]
425+
cksum = payloadcksm[len(payloadcksm)-ChecksumHashLength:]
426+
427+
if protocol == SECP256K1 || protocol == Actor {
428+
if len(payload) != PayloadHashLength {
429+
return Undef, ErrInvalidLength
430+
}
431+
}
432+
433+
if protocol == BLS {
434+
if len(payload) != BlsPublicKeyBytes {
435+
return Undef, ErrInvalidLength
436+
}
437+
}
350438
}
351439

352-
if !ValidateChecksum(append([]byte{protocol}, payload...), cksm) {
440+
if !ValidateChecksum(append([]byte{protocol}, payload...), cksum) {
353441
return Undef, ErrInvalidChecksum
354442
}
355443

0 commit comments

Comments
 (0)