## 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* |

#### LE Audio Sharing Advertising payload: Fast Pair Model ID Data and FP Capability Map

The service data shall contain the following:

| Octet | Data type | Description | Value |
|---|---|---|---|
| 0 | `uint8` | Version and flags 0bVVVVFFFF - V = version - F = flags | `0x00` |
| 1 | `uint8` | Field length and type 0bLLLLTTTT - L = length of the model ID in bytes - T = type | 0bLLLL0111 - length = 0bLLLL = *varies* - type = 0b0111, Model ID |
| 2 - **s** |   | Model ID | *varies* |
| **s** + 1 | `uint8` | Field length and type 0bLLLLTTTT - L = length in bytes - T = type | 0bLLLL1000 - length = 0bLLLL = *varies*, 1 for now - type = 0b1000, [FP Capability Map](https://developers.google.com/nearby/fast-pair/specifications/service/provider#CapabilityMap) |
| **s** + 2 | `uint8` | FP Capability Map | *varies* |

##### FP Capability Map

The FP Capability Map is a bitmap representing which FP features the
Provider supports. The first byte of the bitmap is defined as follows:

| Bitmap | Description |
|---|---|
| 0bRRRRRRSO | R - Reserved bit, will be ignored by seeker for now and shall be set as 0. S - FP LE Audio Sharing support (set to 1 if enabled else 0). O - Out of Box (OOB) bit, set to 1 if the device is factory new. |

If the Provider supports the FP LE Audio Sharing specification (meaning it
supports [Temporary Pairing](https://developers.google.com/nearby/fast-pair/specifications/characteristics#AccountKey "Temporary pairing"),
[LE Audio Sharing Advertising Payload](https://developers.google.com/nearby/fast-pair/specifications/service/provider#AudioSharingPayload), and
[Hearable control version 2](https://developers.google.com/nearby/fast-pair/specifications/extensions/hearablecontrols#ANCControlData "Hearable Control")), set the FP LE Audio Sharing support bit to 1;
otherwise, set it to 0.

If the Provider has not paired with any FP Seeker and is factory new (meaning
there are no FP account keys on the provider), set OOB bit to 1; otherwise, set
it to 0.

#### Coordinated Set Info Advertising payload: Fast Pair Model ID Data and FP Coordinated Set Info

The service data shall contain the following:

| Octet | Data type | Description | Value |
|---|---|---|---|
| 0 | `uint8` | Version and flags 0bVVVVFFFF - V = version - F = flags | `0x00` |
| 1 | `uint8` | Field length and type 0bLLLLTTTT - L = length of the model ID in bytes - T = type | 0bLLLL0111 - length = 0bLLLL = *varies* - type = 0b0111, Model ID |
| 2 - **s** |   | Model ID | *varies* |
| **s** + 1 | `uint8` | Field length and type 0bLLLLTTTT - L = length of coordinated set data - T = type | 0b01101011 - length = 0b0110 - type = 0b1011 |
| **s** + 2 - **s** + 7 | `uint48` | FP Coordinated Set Data | 6-byte data, see [FP Coordinated Set Info](https://developers.google.com/nearby/fast-pair/specifications/service/provider#FpCoordinatedSetInfo) |

##### FP Coordinated Set Info

The FP Coordinated Set Info is used to identity if the advertising device is
in the same Coordinated Set or not.

| Octet | Data type | Description | Value |
|---|---|---|---|
| 0 | `uint8` | Coordinated Set Size | varies |
| 1 | `uint8` | Fast Pair Coordinated Set Member Type | Can be one of - 0x00 : left component - 0x01 : right component |
| 2 - 5 | `uint32` | Set Identity Resolving Key Hash | varies |

The algorithm to generate hash value of Set Identity Resolving Key is

- Use SHA256 to hash the SIRK value

      SIRK = 0xe3b0c44298fc1c149afbf4c8996fb924

      SHA256(SIRK) = 0x2646036bb22781536be710245c8cbb04b92842c587f845996ce8ab542592a25e

- Extract the first four bytes as the hash value

      Hash Value of Set Identity Resolving Key = 0x2646036b

For the Set Identity Resolving Key, see
[Coordinated Set Identification Service](https://www.bluetooth.com/specifications/specs/coordinated-set-identification-service1-1/) for more information.

### 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* |

> [!NOTE]
> **Note:** The provider shall advertise its Fast PairAccount Data only if the Account Key List has one or more entries.

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](https://developers.google.com/nearby/fast-pair/specifications/service/provider#SaltField) |
| *s* + 2 - *s* + 3 | `uint16` | Salt | *varies* |

#### Account Key Filter

> [!NOTE]
> **Note:** Google recommends implementing the [Cryptographic Test Cases](https://developers.google.com/nearby/fast-pair/specifications/appendix/cryptotestcases "Link to the Cryptographic Test Cases.") to ease verification of these requirements.

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](https://en.wikipedia.org/wiki/Bloom_filter) constructed as
follows:

1. Let *n* be the number of account keys (*n* \>= 1) in the persisted [Account Key list](https://developers.google.com/nearby/fast-pair/specifications/configuration#AccountKeyList "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](https://developers.google.com/nearby/fast-pair/specifications/configuration#AccountKeyList "Account Key List"):  

   a. Let *V* be concat(*K* , [Salt](https://developers.google.com/nearby/fast-pair/specifications/service/provider#SaltField)).  

       // 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* =
   {H~0~, ..., H~31~}.

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

   c. Divide *H* into eight 4-byte unsigned integers in big-endian,
   X = {X~0~, ..., X~7~}, where
   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);
            }

   d. For each X~i~:  

   i. Let *M* be *X~i~* 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.