github.com/yggdrasil-network/yggdrasil-go@v0.5.6/src/address/address.go (about)

     1  // Package address contains the types used by yggdrasil to represent IPv6 addresses or prefixes, as well as functions for working with these types.
     2  // Of particular importance are the functions used to derive addresses or subnets from a NodeID, or to get the NodeID and bitmask of the bits visible from an address, which is needed for DHT searches.
     3  package address
     4  
     5  import (
     6  	"crypto/ed25519"
     7  )
     8  
     9  // Address represents an IPv6 address in the yggdrasil address range.
    10  type Address [16]byte
    11  
    12  // Subnet represents an IPv6 /64 subnet in the yggdrasil subnet range.
    13  type Subnet [8]byte
    14  
    15  // GetPrefix returns the address prefix used by yggdrasil.
    16  // The current implementation requires this to be a multiple of 8 bits + 7 bits.
    17  // The 8th bit of the last byte is used to signal nodes (0) or /64 prefixes (1).
    18  // Nodes that configure this differently will be unable to communicate with each other using IP packets, though routing and the DHT machinery *should* still work.
    19  func GetPrefix() [1]byte {
    20  	return [...]byte{0x02}
    21  }
    22  
    23  // IsValid returns true if an address falls within the range used by nodes in the network.
    24  func (a *Address) IsValid() bool {
    25  	prefix := GetPrefix()
    26  	for idx := range prefix {
    27  		if (*a)[idx] != prefix[idx] {
    28  			return false
    29  		}
    30  	}
    31  	return true
    32  }
    33  
    34  // IsValid returns true if a prefix falls within the range usable by the network.
    35  func (s *Subnet) IsValid() bool {
    36  	prefix := GetPrefix()
    37  	l := len(prefix)
    38  	for idx := range prefix[:l-1] {
    39  		if (*s)[idx] != prefix[idx] {
    40  			return false
    41  		}
    42  	}
    43  	return (*s)[l-1] == prefix[l-1]|0x01
    44  }
    45  
    46  // AddrForKey takes an ed25519.PublicKey as an argument and returns an *Address.
    47  // This function returns nil if the key length is not ed25519.PublicKeySize.
    48  // This address begins with the contents of GetPrefix(), with the last bit set to 0 to indicate an address.
    49  // The following 8 bits are set to the number of leading 1 bits in the bitwise inverse of the public key.
    50  // The bitwise inverse of the key, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the address.
    51  func AddrForKey(publicKey ed25519.PublicKey) *Address {
    52  	// 128 bit address
    53  	// Begins with prefix
    54  	// Next bit is a 0
    55  	// Next 7 bits, interpreted as a uint, are # of leading 1s in the NodeID
    56  	// Leading 1s and first leading 0 of the NodeID are truncated off
    57  	// The rest is appended to the IPv6 address (truncated to 128 bits total)
    58  	if len(publicKey) != ed25519.PublicKeySize {
    59  		return nil
    60  	}
    61  	var buf [ed25519.PublicKeySize]byte
    62  	copy(buf[:], publicKey)
    63  	for idx := range buf {
    64  		buf[idx] = ^buf[idx]
    65  	}
    66  	var addr Address
    67  	var temp = make([]byte, 0, 32)
    68  	done := false
    69  	ones := byte(0)
    70  	bits := byte(0)
    71  	nBits := 0
    72  	for idx := 0; idx < 8*len(buf); idx++ {
    73  		bit := (buf[idx/8] & (0x80 >> byte(idx%8))) >> byte(7-(idx%8))
    74  		if !done && bit != 0 {
    75  			ones++
    76  			continue
    77  		}
    78  		if !done && bit == 0 {
    79  			done = true
    80  			continue // FIXME? this assumes that ones <= 127, probably only worth changing by using a variable length uint64, but that would require changes to the addressing scheme, and I'm not sure ones > 127 is realistic
    81  		}
    82  		bits = (bits << 1) | bit
    83  		nBits++
    84  		if nBits == 8 {
    85  			nBits = 0
    86  			temp = append(temp, bits)
    87  		}
    88  	}
    89  	prefix := GetPrefix()
    90  	copy(addr[:], prefix[:])
    91  	addr[len(prefix)] = ones
    92  	copy(addr[len(prefix)+1:], temp)
    93  	return &addr
    94  }
    95  
    96  // SubnetForKey takes an ed25519.PublicKey as an argument and returns a *Subnet.
    97  // This function returns nil if the key length is not ed25519.PublicKeySize.
    98  // The subnet begins with the address prefix, with the last bit set to 1 to indicate a prefix.
    99  // The following 8 bits are set to the number of leading 1 bits in the bitwise inverse of the key.
   100  // The bitwise inverse of the key, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the subnet.
   101  func SubnetForKey(publicKey ed25519.PublicKey) *Subnet {
   102  	// Exactly as the address version, with two exceptions:
   103  	//  1) The first bit after the fixed prefix is a 1 instead of a 0
   104  	//  2) It's truncated to a subnet prefix length instead of 128 bits
   105  	addr := AddrForKey(publicKey)
   106  	if addr == nil {
   107  		return nil
   108  	}
   109  	var snet Subnet
   110  	copy(snet[:], addr[:])
   111  	prefix := GetPrefix() // nolint:staticcheck
   112  	snet[len(prefix)-1] |= 0x01
   113  	return &snet
   114  }
   115  
   116  // GetKet returns the partial ed25519.PublicKey for the Address.
   117  // This is used for key lookup.
   118  func (a *Address) GetKey() ed25519.PublicKey {
   119  	var key [ed25519.PublicKeySize]byte
   120  	prefix := GetPrefix() // nolint:staticcheck
   121  	ones := int(a[len(prefix)])
   122  	for idx := 0; idx < ones; idx++ {
   123  		key[idx/8] |= 0x80 >> byte(idx%8)
   124  	}
   125  	keyOffset := ones + 1
   126  	addrOffset := 8*len(prefix) + 8
   127  	for idx := addrOffset; idx < 8*len(a); idx++ {
   128  		bits := a[idx/8] & (0x80 >> byte(idx%8))
   129  		bits <<= byte(idx % 8)
   130  		keyIdx := keyOffset + (idx - addrOffset)
   131  		bits >>= byte(keyIdx % 8)
   132  		idx := keyIdx / 8
   133  		if idx >= len(key) {
   134  			break
   135  		}
   136  		key[idx] |= bits
   137  	}
   138  	for idx := range key {
   139  		key[idx] = ^key[idx]
   140  	}
   141  	return ed25519.PublicKey(key[:])
   142  }
   143  
   144  // GetKet returns the partial ed25519.PublicKey for the Subnet.
   145  // This is used for key lookup.
   146  func (s *Subnet) GetKey() ed25519.PublicKey {
   147  	var addr Address
   148  	copy(addr[:], s[:])
   149  	return addr.GetKey()
   150  }