Рекламный сигнал поставщика
Реклама: Когда ее можно обнаружить
Когда устройство поставщика доступно для обнаружения BR/EDR (то есть находится в режиме сопряжения), оно должно передавать данные идентификатора модели Fast Pair через BLE, а адрес BLE не должен меняться.
Интервал показа рекламы: Когда возможно обнаружение
Интервал между объявлениями не должен превышать 100 мс (10 Гц). Высокая скорость позволяет Seeker быстро находить провайдера, даже при сканировании в режиме низкого энергопотребления.
Рекламная полезная нагрузка: данные идентификатора модели Fast Pair
Реклама должна содержать тип данных Service Data, там же, § 1.11. UUID должен быть Fast Pair Service UUID 0xFE2C
. Данные службы должны содержать следующее:
Октет | Тип данных | Описание | Ценить |
---|---|---|---|
0-2 | uint24 | 24-битный идентификатор модели | варьируется |
Реклама: когда ее невозможно обнаружить
Если устройство Поставщика не может быть обнаружено (то есть не находится в режиме сопряжения), оно должно публиковать данные учетной записи Fast Pair, используя следующие рекомендации.
Реклама данных учетной записи позволяет Seekers поблизости распознавать, когда поставщик принадлежит их учетной записи, и инициировать сопряжение без необходимости принудительно возвращать поставщика в режим сопряжения, что является распространенной причиной жалоб пользователей. Seekers предоставит пользователям возможность игнорировать эту трансляцию в случае, если они не ждут сопряжения с провайдером или трансляция неактуальна (например, если они уже сопряжены). Seekers также автоматически отфильтрует явно плохие трансляции, например, когда данные учетной записи неправильно настроены.
Интервал показа рекламы: когда не обнаруживается
Интервал между рекламными объявлениями должен составлять не более 250 мс (4 Гц).
Рекламная нагрузка: данные учетной записи Fast Pair
Реклама должна содержать тип данных Service Data, Ibid., § 1.11. UUID должен быть Fast Pair Service UUID 0xFE2C
. Данные службы должны содержать следующее:
Октет | Тип данных | Описание | Ценить |
---|---|---|---|
0 | uint8 | Версия и флаги 0бВВВВФФФФ
| 0x00 (зарезервировано для будущего использования) |
1 - варьируется | Ключевые данные учетной записи | варьируется |
Ключевые данные учетной записи содержат:
Октет | Тип данных | Описание | Ценить |
---|---|---|---|
0 | uint8 | Длина и тип поля 0бЛЛЛЛТТТ
| 0бЛЛЛЛ0000
|
1 - с | Фильтр ключа учетной записи | варьируется | |
с + 1 | uint8 | Длина и тип поля 0бЛЛЛЛТТТ
| 0б00100001
|
с + 2 - с + 3 | uint16 | Соль | варьируется |
Фильтр ключа учетной записи
Рекламируемый фильтр ключей учетной записи позволяет Seeker быстро проверить, может ли Provider обладать определенным ключом учетной записи (с низкой вероятностью ложного срабатывания, в среднем намного меньше 0,5%), перед дальнейшим взаимодействием. Seeker может автоматически подключиться и попытаться запустить процедуру, когда он видит, что фильтр транслируется с типом 0, т. е. показывает индикацию пользовательского интерфейса, которая потенциально содержит один из его ключей учетной записи, чтобы еще больше снизить частоту ложных срабатываний. В некоторых ситуациях Provider может захотеть, чтобы Seeker распознал его, не будучи готовым к сопряжению. Одним из примеров является то, что когда наушники возвращаются в кейс, мы хотим прекратить показывать последующее уведомление о сопряжении, поскольку это сопряжение может быть отклонено гарнитурой.
Фильтр ключа учетной записи представляет собой фильтр Блума переменной длины, построенный следующим образом:
- Пусть n — количество ключей учетных записей ( n >= 1) в сохраненном списке ключей учетных записей .
- Пусть s , размер фильтра в байтах, будет усечен на (1.2* n + 3). Например, если сохраняется 1 ключ, s = 4 байта.
uint8_t s = (((uint8_t)(( float )1.2 * n)) + 3);
- Инициализируйте фильтр F как массив из s байтов, каждый из которых равен 0.
uint8_t F[s] = {0};
Для каждого ключа учетной записи K в сохраненном списке ключей учетной записи :
а. Пусть V будет concat( K , Salt ).// In the sample code, the size of salt is 2 bytes. #define SALT_SIZE 2 uint8_t V[FASTPAIR_ACCOUNT_KEY_SIZE + SALT_SIZE]; for (uint8_t keyIndex = 0; keyIndex < n; keyIndex++) { // concat (K, Salt) fastpair_get_account_key_by_index(keyIndex, V); uint8_t randomSalt = (uint8_t)rand(); V[FASTPAIR_ACCOUNT_KEY_SIZE] = randomSalt; ... }
б) Хэшируем V с помощью SHA256, получая 32-байтовое значение H = {H 0 , …, H 31 }.
uint8_t H[32] = {0}; SHA256_hash_function(V, H);
в) Разделить H на восемь 4-байтовых беззнаковых целых чисел в обратном порядке, X = {X 0 , …, X 7 }, где X 0 = 0xH 0 H 1 H 2 H 3 .
uint32_t X[8]; for (index = 0; index < 8; index++) { X[index] = (((uint32_t)(H[index * 4])) << 24) | (((uint32_t)(H[index * 4 + 1])) << 16) | (((uint32_t)(H[index * 4 + 2])) << 8) | (((uint32_t)(H[index * 4 + 3])) << 0); }
г. Для каждого X i :
i. Пусть M будет X i по модулю числа бит в фильтре ( s * 8).
ii. Получить байт в F по индексу ( M / 8), округленный в меньшую сторону.
iii. Внутри байта установите бит с индексом ( M % 8) на 1.
iv. Другими словами:// M = Xi % (s * 8) // F[M/8] = F[M/8] | (1 << (M % 8)) for (index = 0; index < 8; index++) { uint32_t M = X[index] % (s * 8); F[M / 8] = F[M / 8] | (1 << (M % 8)); }
Включите фильтр F как поле Account Key Filter в рекламных данных. Обратите внимание, что в этом значении нет «порядка байтов», поскольку нет более или менее значимого байта — не меняйте порядок байтов.
Соляное поле
Соль — это случайное значение, которое добавляется к ключам учетной записи при построении фильтра Блума. Эту соль следует регенерировать каждый раз при обновлении RPA для Поставщика, чтобы избежать отслеживания через ротацию адресов.
Чтобы сгенерировать фильтр ключа учетной записи с использованием соли:
- Сгенерируйте случайное 2-байтовое значение S. Обратите внимание, что для этого значения нет «порядка байтов», поскольку нет более или менее значимого байта — не меняйте порядок байтов.
- Используйте 2-байтовый S в качестве соли.
- В объявленных данных учетной записи Fast Pair включите сгенерированный фильтр в поле Фильтр ключа учетной записи и S в поле Соль.