PRId

A Pseudonymous Relationship Identifier is represented by the PRId object type.

Serialization

PRId object serialization MUST conform to the following Avro schema:

{
    "namespace": "org.dsnp",
    "name": "PRId",
    "type": "fixed",
    "size": 8,
    "doc": "Pseudonymous Relationship Identifier"
}

Generation

PRIds are generated cryptographically to represent a relationship from one user to another within a specified context, in a privacy-preserving manner.

Contexts

The following context values are currently defined for PRIds. All other values are reserved for future use.

Context IdDescriptionContext string
0ConnectionPRIdCtx0

Algorithm

In the following section, the Alice to Bob identifier for context C is called PRIdA→B,C, and the corresponding Bob to Alice identifier is called PRIdB→A,C.

A PRId is derived from Alice and Bob's keyAgreement key pairs, using a key exchange protocol as follows. To illustrate the cryptographic operations required, the relevant functions from libsodium are noted. Sodium is a stable, fast, free, and cross-platform cryptography library, and supports all encryption algorithms used in the DSNP specification out of the box.

Definitions:

  • IdA = DSNP User Id of A (little-endian)
  • IdB = DSNP User Id of B (little-endian)

Algorithm:

  1. Both Alice and Bob generate an asymmetric key pair for use with X25519 ECIES. Each publishes a Public Key Announcement with their generated public key with a keyType value of keyAgreement.
LibsodiumAlgorithm
crypto_box_keypair(
  &a_public,
  &a_secret);
crypto_box_keypair(
  &b_public, 
  &b_secret);
  
(Apublic, Asecret) ← KGF()
(Bpublic, Bsecret) ← KGF()
  1. When Alice wants to interact with Bob, she looks up Bob's public key and performs an X25519 Elliptic-curve Diffie-Hellman key exchange operation using her secret key and Bob's public key, generating a root shared secret.
LibsodiumAlgorithm
crypto_box_beforenm(
  &root_shared_secret,
  b_public,
  a_secret);
RootSharedSecretABECDH(Bpublic, Asecret)
  1. Alice derives a context-specific subkey CtxSharedSecretBob from the shared secret RootSharedSecret as the master key, Bob's DSNP User Id as the 64-bit key identifier, and the ASCII encoding of the PRId Context string ("PRIdCtx0" for connections).
LibsodiumAlgorithm
crypto_kdf_derive_from_key(
  ctx_shared_secret,
  32,
  b_user_id,
  "PRIdCtx0",
  root_shared_secret);
CtxSharedSecretA→B ←
  Blake2b256(
    key = RootSharedSecretAB,
    message = {},
    salt = IdB || {0},
    personal = "PRIdCtx0" || {0})
  1. Alice uses Bob's DSNP User Id to form an 8-byte little-endian message. Alice encrypts this message using XSalsa20 with the PRId key CtxSharedSecretA→B and a nonce of her own User Id (little-endian) followed by 16 zero bytes.
LibsodiumAlgorithm
char nonce[24] = {0};
int i;
for (i = 0; i < 8; i++) {
  nonce[i] = (user_id_a >> (i*8))
    & 0xff;
}
crypto_secretbox_detached( &prid, &mac_unused, user_id_b, 8, nonce, ctx_shared_secret);
  • Alice's act of publishing provides authentication, so the MAC is unused.
PRIdA→B,C ←
  XSalsa20(
    message = IdB,
    key = CtxSharedSecretA→B,
    nonce = Padded24BytesLE(IdA)
  )
  1. Alice adds the generated PRId to the relevant list of PRIds and publishes an updated copy via the Replace User Data Operation.

Similarly, Bob can calculate the same root shared secret RootSharedSecret using Alicepublic and Bobsecret and derive the same PRIdA→B,C in order to check if it is in Alice's published PRIds. Bob can also derive the PRId subkey for Alice's DSNP User Id and encrypt Alice's User Id, using his own as the nonce, to generate the Bob-to-Alice PRId (PRIdB→A,C), and then publish it to his own list, if desired.

If Alice or Bob wants to prove to a third party that their PRIds are in each other's PRId list, they can provide the third party with their own subkey CtxSharedSecretA→B or CtxSharedSecretB→A. The third party can repeat the encryption step using Alice and Bob's User Ids, and check that the output is present in the published set of PRIds. The root shared secret RootSharedSecret (used as a master key in this algorithm) should not be divulged.

Test Vector

For the following inputs:

InputValue
Asecret0xc9432ed5c0c5c24e8a4ff190619893918b4d1265a67d123895023fa7324b43e0
Apublic0x0fea2cafabdc83752be36fa5349640da2c828add0a290df13cd2d8173eb2496f
Bsecret0xdc106e1371293ee9536956e1253f43f8941d4a5c4e40f15968d24b75512b6920
Bpublic0xd0d4eb21db1df63369c147e63b2573816dd4b3fe513e95bf87f7ed1835407e62
IdA42
IdB478
ContextPRIdCtx0

An implementation of the PRId generation algorithm should produce the following outputs:

OutputValue
PRIdA→B0xace4d2995b1a829c
CtxSharedSecretA→B0x37cb1a870f0c1dce06f5116faf145ac2cf7a2f7d30136be4eea70c324932e6d2
PRIdB→A0x1a53b02a26503600
CtxSharedSecretB→A0x32c45c49fcfe12f9db60e74fa66416c5a05832c298814d82032a6783a4b1fca0