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 privacypreserving manner.
Contexts
The following context values are currently defined for PRIds. All other values are reserved for future use.
Context Id  Description  Context string 

0  Connection  PRIdCtx0 
Algorithm
In the following section, the Alice to Bob identifier for context C is called PRId_{A→B,C}, and the corresponding Bob to Alice identifier is called PRId_{B→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 crossplatform cryptography library, and supports all encryption algorithms used in the DSNP specification out of the box.
Definitions:
Id_{A} = DSNP User Id of A (littleendian)
Id_{B} = DSNP User Id of B (littleendian)
Algorithm:
 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 ofkeyAgreement
.
Libsodium  Algorithm 

crypto_box_keypair( &a_public, &a_secret); crypto_box_keypair( &b_public, &b_secret); 
(A_{public}, A_{secret}) ← KGF() (B_{public}, B_{secret}) ← KGF() 
 When Alice wants to interact with Bob, she looks up Bob's public key and performs an X25519 Ellipticcurve DiffieHellman key exchange operation using her secret key and Bob's public key, generating a root shared secret.
Libsodium  Algorithm 

crypto_box_beforenm( &root_shared_secret, b_public, a_secret); 
RootSharedSecret_{AB} ← ECDH(B_{public}, A_{secret}) 
 Alice derives a contextspecific subkey
CtxSharedSecret_{Bob}
from the shared secretRootSharedSecret
as the master key, Bob's DSNP User Id as the 64bit key identifier, and the ASCII encoding of the PRId Context string ("PRIdCtx0"
for connections).
Libsodium  Algorithm 

crypto_kdf_derive_from_key( ctx_shared_secret, 32, b_user_id, "PRIdCtx0", root_shared_secret); 
CtxSharedSecret_{A→B} ← Blake2b_{256}( key = RootSharedSecret_{AB}, message = {}, salt = Id_{B}  {0}, personal = "PRIdCtx0"  {0}) 
 Alice uses Bob's DSNP User Id to form an 8byte littleendian message.
Alice encrypts this message using XSalsa20 with the PRId key
CtxSharedSecret_{A→B}
and a nonce of her own User Id (littleendian) followed by 16 zero bytes.
Libsodium  Algorithm 

char nonce[24] = {0}; int i; for (i = 0; i < 8; i++) { nonce[i] = (user_id_a >> (i*8)) & 0xff; }

PRId_{A→B,C} ← XSalsa20( message = Id_{B}, key = CtxSharedSecret_{A→B}, nonce = Padded24BytesLE(Id_{A}) ) 
 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 Alice_{public}
and Bob_{secret}
and derive the same PRId_{A→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 BobtoAlice PRId (PRId_{B→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 CtxSharedSecret_{A→B}
or CtxSharedSecret_{B→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:
Input  Value 

A_{secret}  0xc9432ed5c0c5c24e8a4ff190619893918b4d1265a67d123895023fa7324b43e0 
A_{public}  0x0fea2cafabdc83752be36fa5349640da2c828add0a290df13cd2d8173eb2496f 
B_{secret}  0xdc106e1371293ee9536956e1253f43f8941d4a5c4e40f15968d24b75512b6920 
B_{public}  0xd0d4eb21db1df63369c147e63b2573816dd4b3fe513e95bf87f7ed1835407e62 
Id_{A}  42 
Id_{B}  478 
Context  PRIdCtx0 
An implementation of the PRId generation algorithm should produce the following outputs:
Output  Value 

PRId_{A→B}  0xace4d2995b1a829c 
CtxSharedSecret_{A→B}  0x37cb1a870f0c1dce06f5116faf145ac2cf7a2f7d30136be4eea70c324932e6d2 
PRId_{B→A}  0x1a53b02a26503600 
CtxSharedSecret_{B→A}  0x32c45c49fcfe12f9db60e74fa66416c5a05832c298814d82032a6783a4b1fca0 