Provider Advertising signal

Advertising: When discoverable

When the Provider device is BR/EDR discoverable (that is, in pairing mode), it shall advertise Fast Pair Model ID Data over BLE, and the BLE address shall not be rotated.

Advertising interval: When discoverable

The interval between advertisements should be no larger than 100ms (10Hz). A fast rate allows the Seeker to quickly find the Provider, even when scanning in low-power mode.

Advertising payload: Fast Pair Model ID Data

The advertisement shall contain the Service Data data type, ibid., § 1.11. The UUID shall be the Fast Pair Service UUID of 0xFE2C. The service data shall contain the following:

Octet Data type Description Value
0-2 uint24 24-bit model ID varies

Advertising: When not discoverable

When not discoverable (that is, not in pairing mode), the Provider device shall advertise Fast Pair Account Data, using the following guidelines.

Advertising the account data allows Seekers nearby to recognize when a provider belongs to their account and initiate pairing without having to force the provider back into pairing mode first, which is a common cause for user complaint. Seekers will provide the opportunity for users to be able to ignore this broadcast in the case where they do not wait to pair with the provider or the broadcast is not relevant (for example, if they have already paired). Seekers will also filter out obviously bad broadcasts automatically, such as when the account data is misconfigured.

Advertising interval: When not discoverable

The interval between advertisements should be at most 250ms (4Hz).

Advertising payload: Fast Pair Account Data

The advertisement shall contain the Service Data data type, Ibid., § 1.11. The UUID shall be the Fast Pair Service UUID of 0xFE2C. The service data shall contain the following:

Octet Data type Description Value
0 uint8 Version and flags
0bVVVVFFFF
  • V = version
  • F = flags
0x00
(reserved for future use)
1 - varies Account Key Data varies
or 0x00 if the Account Key List is empty

The Account Key Data contains:

Octet Data type Description Value
0 uint8 Field length and type
0bLLLLTTTT
  • L = length of account key filter in bytes
  • T = type
0bLLLL0000
  • length = 0bLLLL = varies
  • type = 0b0000 (show UI indication) or 0b0010 (hide UI indication), Account Key Filter
1 - s Account Key Filter varies
s + 1 uint8 Field length and type
0bLLLLTTTT
  • L = length in bytes
  • T = type
0b00100001
  • length = 0b0010 = 2
  • type = 0b0001, Salt
s + 2 - s + 3 uint16 Salt varies

Account Key Filter

The advertised Account Key Filter allows a Seeker to quickly check whether a Provider might possess a certain account key (with a low false-positive probability, on average much less than 0.5%), before further interactions. The Seeker may automatically connect and attempt to start the procedure when it sees a filter being broadcast with type 0, i.e. showing UI indication, that potentially contains one of its account keys, so as to reduce the rate of false positives further. In some situations, the Provider may want to be recognized by the Seeker while not ready for pairing. One example is that when buds get put back into case, we want to stop showing the subsequent pairing notification since that pairing could be rejected by the headset.

The Account Key Filter is a variable-length Bloom filter constructed as follows:

  1. Let n be the number of account keys (n >= 1) in the persisted Account Key list.
  2. Let s, the size of the filter in bytes, be (1.2*n + 3) truncated. For example, if 1 key is persisted, s = 4 bytes.
    uint8_t s = (((uint8_t)(( float )1.2 * n)) + 3);
  3. Initialize the filter F as an array of s bytes, each set to 0.
    uint8_t F[s] = {0};
  4. For each account key K in the persisted Account Key list:
    a. Let V be 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;
          ... }
    

    b. Hash V using SHA256, obtaining a 32-byte value H = {H0, …, H31}.

    uint8_t H[32] = {0};
    SHA256_hash_function(V, H);
    

    c. Divide H into eight 4-byte unsigned integers in big-endian, X = {X0, …, X7}, where X0 = 0xH0H1H2H3.

         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);
         }
    

    d. For each Xi:
    i. Let M be Xi modulo the number of bits in the filter, (s * 8).
    ii. Get the byte in F at index (M / 8), rounded down.
    iii. Within the byte, set the bit at index (M % 8) to 1.
    iv. In other words:

        // 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));
        }
    

Include the filter F as the Account Key Filter field, in the advertising data. Note that there is no "endianness" to this value, since there is no more or less significant byte—don't alter the byte order.

Salt field

The salt is a random value that is appended to account keys when building the bloom filter. This salt should be regenerated every time the RPA is updated for the Provider to avoid tracking across address rotation.

To generate the Account Key Filter using the salt:

  1. Generate a random 2-byte S. Note that there is no "endianness" to this value, since there is no more or less significant byte — don't alter the byte order.
  2. Use the 2-byte S as the Salt.
  3. In the advertised Fast Pair Account Data, include the generated filter in the Account Key Filter field, and S in the Salt field.