thali/NextGeneration/notification/thaliNotificationBeacons.js
function generatePskSecrets(publicKeysToNotify,
                            ecdhForLocalDevice,
                            beaconStreamWithPreAmble) {
  var preAmbleSizeInBytes = module.exports.PUBLIC_KEY_SIZE +
    module.exports.EXPIRATION_SIZE;

  var preAmble = beaconStreamWithPreAmble.slice(0, preAmbleSizeInBytes);
  var beaconStreamNoPreAmble =
    beaconStreamWithPreAmble.slice(preAmbleSizeInBytes);

  var beacons = [];
  for (var i = 0; i < beaconStreamNoPreAmble.length;
       i += module.exports.BEACON_SIZE) {
    beacons.push(
      beaconStreamNoPreAmble.slice(i, i + module.exports.BEACON_SIZE));
  }

  assert(beacons.length === publicKeysToNotify.length, 'We should have the' +
    'same number of beacons as public keys to notify');

  var pskMap = {};
  for (i = 0; i < publicKeysToNotify.length; ++i) {
    var pskIdentityField = generatePskIdentityField(preAmble, beacons[i]);
    var pskSecret = generatePskSecret(ecdhForLocalDevice, publicKeysToNotify[i],
      pskIdentityField);
    pskMap[pskIdentityField] = {
      publicKey: publicKeysToNotify[i],
      pskSecret: pskSecret
    };
  }
  return pskMap;
}
function generatePskSecrets(publicKeysToNotify,
                            ecdhForLocalDevice,
                            beaconStreamWithPreAmble) {
  var preAmbleSizeInBytes = module.exports.PUBLIC_KEY_SIZE +
    module.exports.EXPIRATION_SIZE;

  var preAmble = beaconStreamWithPreAmble.slice(0, preAmbleSizeInBytes);
  var beaconStreamNoPreAmble =
    beaconStreamWithPreAmble.slice(preAmbleSizeInBytes);

  var beacons = [];
  for (var i = 0; i < beaconStreamNoPreAmble.length;
       i += module.exports.BEACON_SIZE) {
    beacons.push(
      beaconStreamNoPreAmble.slice(i, i + module.exports.BEACON_SIZE));
  }

  assert(beacons.length === publicKeysToNotify.length, 'We should have the' +
    'same number of beacons as public keys to notify');

  var pskMap = {};
  for (i = 0; i < publicKeysToNotify.length; ++i) {
    var pskIdentityField = generatePskIdentityField(preAmble, beacons[i]);
    var pskSecret = generatePskSecret(ecdhForLocalDevice, publicKeysToNotify[i],
      pskIdentityField);
    pskMap[pskIdentityField] = {
      publicKey: publicKeysToNotify[i],
      pskSecret: pskSecret
    };
  }
  return pskMap;
}
function generatePskSecrets ( publicKeysToNotify , ecdhForLocalDevice , beaconStreamWithPreAmble ) { var preAmbleSizeInBytes = module . exports . PUBLIC_KEY_SIZE + module . exports . EXPIRATION_SIZE ; var preAmble = beaconStreamWithPreAmble . slice ( 0 , preAmbleSizeInBytes ) ; var beaconStreamNoPreAmble = beaconStreamWithPreAmble . slice ( preAmbleSizeInBytes ) ; var beacons = [ ] ; for ( var i = 0 ; i < beaconStreamNoPreAmble . length ; i += module . exports . BEACON_SIZE ) { beacons . push ( beaconStreamNoPreAmble . slice ( i , i + module . exports . BEACON_SIZE ) ) ; } assert ( beacons . length === publicKeysToNotify . length , 'We should have the' + 'same number of beacons as public keys to notify' ) ; var pskMap = { } ; for ( i = 0 ; i < publicKeysToNotify . length ; ++ i ) { var pskIdentityField = generatePskIdentityField ( preAmble , beacons [ i ] ) ; var pskSecret = generatePskSecret ( ecdhForLocalDevice , publicKeysToNotify [ i ] , pskIdentityField ) ; pskMap [ pskIdentityField ] = { publicKey : publicKeysToNotify [ i ] , pskSecret : pskSecret } ; } return pskMap ; }
A dictionary whose key is the identity string sent over TLS and whose
value is a keyAndSecret specifying what publicKey this identity is associated
with and what secret it needs to provide.

@public
@typedef {Object.<string, keyAndSecret>} pskMap
 
This function takes a list of public keys and the device's ECDH private key
along with a beacon stream with preamble that was generated using those
public keys. The function requires that the beacon values in the beacon
stream MUST be in the same order as the keys listed in the publicKeysToNotify
array.

The code will then generate Sxy as given in http://thaliproject.org/PresenceProtocolBindings/#transferring-from-notification-beacon-to-tls
and then feed that to HKDF using the the PSKIdentity value which is defined
in the above as the pre-amble plus the individual beacon value for the
associated public key. This means we have to parse the beacon stream to
pull out the preamble along with the specific associated beacon and then
combine them together into a single buffer that is then base64'd using
the URL safe base64 scheme. This is then fed to HKDF as defined in the
link above which produces the value that will be used as the secret.

This function will then wrap up all of this into a dictionary whose key
is the base64 url safe'd pre-amble + beacon value and who value is the
secret along with the associated publicKey.

@param {Buffer[]} publicKeysToNotify - An array of buffers holding ECDH
public keys.
@param {ECDH} ecdhForLocalDevice - A Crypto.ECDH object initialized with the
local device's public and private keys
@param {Buffer} beaconStreamWithPreAmble - A buffer stream containing the
preamble and beacons
@returns {pskMap|Error}
A dictionary whose key is the identity string sent over TLS and whose value is a keyAndSecret specifying what publicKey this identity is associated with and what secret it needs to provide .