7
7
"io"
8
8
"math"
9
9
"strconv"
10
+ "strings"
10
11
11
12
cbor "github.com/ipfs/go-ipld-cbor"
12
13
"github.com/minio/blake2b-simd"
@@ -69,6 +70,8 @@ const (
69
70
Actor
70
71
// BLS represents the address BLS protocol.
71
72
BLS
73
+ // Delegated represents the delegated (f4) address protocol.
74
+ Delegated
72
75
73
76
Unknown = Protocol (255 )
74
77
)
@@ -177,6 +180,19 @@ func NewBLSAddress(pubkey []byte) (Address, error) {
177
180
return newAddress (BLS , pubkey )
178
181
}
179
182
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
+
180
196
// NewFromString returns the address represented by the string `addr`.
181
197
func NewFromString (addr string ) (Address , error ) {
182
198
return decode (addr )
@@ -209,8 +225,9 @@ func addressHash(ingest []byte) []byte {
209
225
}
210
226
211
227
// 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.
214
231
func newAddress (protocol Protocol , payload []byte ) (Address , error ) {
215
232
switch protocol {
216
233
case ID :
@@ -233,6 +250,17 @@ func newAddress(protocol Protocol, payload []byte) (Address, error) {
233
250
if len (payload ) != BlsPublicKeyBytes {
234
251
return Undef , ErrInvalidLength
235
252
}
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
+ }
236
264
default :
237
265
return Undef , ErrUnknownProtocol
238
266
}
@@ -259,17 +287,33 @@ func encode(network Network, addr Address) (string, error) {
259
287
return UndefAddressString , ErrUnknownNetwork
260
288
}
261
289
290
+ protocol := addr .Protocol ()
291
+ payload := addr .Payload ()
262
292
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 [:]... ))
267
311
case ID :
268
- i , n , err := varint .FromUvarint (addr . Payload () )
312
+ i , n , err := varint .FromUvarint (payload )
269
313
if err != nil {
270
314
return UndefAddressString , xerrors .Errorf ("could not decode varint: %w" , err )
271
315
}
272
- if n != len (addr . Payload () ) {
316
+ if n != len (payload ) {
273
317
return UndefAddressString , xerrors .Errorf ("payload contains additional bytes" )
274
318
}
275
319
strAddr = fmt .Sprintf ("%s%d%d" , ntwk , addr .Protocol (), i )
@@ -279,6 +323,19 @@ func encode(network Network, addr Address) (string, error) {
279
323
return strAddr , nil
280
324
}
281
325
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
+
282
339
func decode (a string ) (Address , error ) {
283
340
if len (a ) == 0 {
284
341
return Undef , nil
@@ -304,6 +361,8 @@ func decode(a string) (Address, error) {
304
361
protocol = Actor
305
362
case '3' :
306
363
protocol = BLS
364
+ case '4' :
365
+ protocol = Delegated
307
366
default :
308
367
return Undef , ErrUnknownProtocol
309
368
}
@@ -320,36 +379,65 @@ func decode(a string) (Address, error) {
320
379
return newAddress (protocol , varint .ToUvarint (id ))
321
380
}
322
381
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 ]
332
390
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
+ }
336
398
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
+ }
339
403
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 {
342
410
return Undef , ErrInvalidLength
343
411
}
344
- }
345
412
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 {
348
421
return Undef , ErrInvalidLength
349
422
}
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
+ }
350
438
}
351
439
352
- if ! ValidateChecksum (append ([]byte {protocol }, payload ... ), cksm ) {
440
+ if ! ValidateChecksum (append ([]byte {protocol }, payload ... ), cksum ) {
353
441
return Undef , ErrInvalidChecksum
354
442
}
355
443
0 commit comments