/// <summary> /// Computes a cryptographically secure random Kademlia key that matches the boundaries of this <see cref="IBucket"/>. /// </summary> /// <returns></returns> public static string GetRandomKey(string key, int index) { byte[] keyBytes = EncryptionProvider.GetBytes(key); byte[] bytes = GetRandomKey(); int sharedPrefixLengthBytes = (int)Math.Floor((index / (decimal)8)); int sharedPrefixLengthBits = index % 8; CryptoRandom cryptoRandom = new CryptoRandom(); for (int i = 0; i < keyBytes.Length; i++) { if (i > sharedPrefixLengthBytes) { // Keep randomness bytes[i] = (byte)(bytes[i] ^ keyBytes[i]); } else if (i < sharedPrefixLengthBytes) { // Use the bytes from the given key bytes[i] = keyBytes[i]; } else if (i == sharedPrefixLengthBytes) { // Preserve some random bits without modifying the most significant bit index int min = (255 >> (sharedPrefixLengthBits + 1)) + 1; int max = (255 >> sharedPrefixLengthBits) + 1; int shift = cryptoRandom.Next(min, max); bytes[i] = (byte)(shift ^ keyBytes[i]); } } return(EncryptionProvider.GetString(bytes)); }
/// <summary> /// Computes the distance between the specified node ids. /// </summary> /// <param name="nodeId1"></param> /// <param name="nodeId2"></param> /// <returns></returns> internal static byte[] DistanceBytes(string nodeId1, string nodeId2) { if (string.IsNullOrEmpty(nodeId1)) { throw new ArgumentNullException("nodeId1"); } if (string.IsNullOrEmpty(nodeId2)) { throw new ArgumentNullException("nodeId2"); } if (nodeId1.Length != nodeId2.Length) { throw new ArgumentException("The specified node ids must be of equal length"); } byte[] nodeId1Bytes = EncryptionProvider.GetBytes(nodeId1); byte[] nodeId2Bytes = EncryptionProvider.GetBytes(nodeId2); // Compute XOR byte[] distance = new byte[nodeId1Bytes.Length]; for (int i = distance.Length - 1; i >= 0; i--) { distance[i] = (byte)(nodeId1Bytes[i] ^ nodeId2Bytes[i]); } return(distance); }