specs/standards/application/rln-keystore.md

12 KiB
Raw Blame History

title name category editor contributors
WAKU-RLN-KEYSTORE Waku RLN Keystore Standards Track Jimmy Debe <jimmy@status.im>
Aaryamann Challani <aaryamann@status.im>

Abstract

This specification describes how RLN, Rate Limit Nullifier, credentials are securely stored in a JSON schema.

Summary

A keystore is a construct to store a users keys. The keys will be encrypted and decrypted based on methods specified in this specification. The keystore stores a user's credentials locally and uses 32/RLN-V1 as a spam-prevention mechanism by generating zero-knowledge proofs.

Background

The secure storage of keys is important in peer-to-peer messaging applications. A WAKU-RLN-KEYSTORE uses zero-knowledge proofs for anonymous rate-limiting for messaging frameworks. Generated credentials by a user are encrypted and stored in the keystore to be retrieved over a network. With 32/RLN-V1, sending and receiving messages will ensure a message rate for a network is being followed while preserving the anonymity of the message owner.

Waku RLN Keystore Format:

A format example of a keystore used by a 17/WAKU2-RLN-Relay.

const Keystore {
	application: "waku-rln-relay" ,
	appIdentifier: "string",
	version: "string",
	credentials: {
    		"membershipHash": {
      			crypto: {
        			cipher: "string",
        			cipherparams: {
					iv: "string",
				},
        			ciphertext: "string",
        			kdf: "string",
        			kdfparams: {
          				dklen: integer,
          				c: integer,
          				prf: "string",
          				salt: "string",
        			},
        			mac: "string",
      			}
    		}
	}
}

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

The keystore MUST be generated by a cryptographic construction with password verification and decryption.

Keystore modules MUST include metadata, key derivation function, checksum, cipher, and a membership hash.

Metadata:

Information about the keystore SHOULD be stored in the metadata.

The declaration of application, version, and appIdentifier COULD occur in the metadata.

  • application : current application, MUST be a string
  • version : application version, MUST be a string, SHOULD follow semantic versioning
  • appIdentifier: application identifier, MUST be a string

Credentials:

After RLN credentials are generated, it MUST be stored in a JSON schema. The Waku RLN credentials MUST consist of a membershipHash and WakuCredential. The membershipHash will be an identity hash of the user. The WakuCredential will store to encryption portion of the keystore. There COULD be multiple credentials stored in a keystore, categorized by the membershipHash.

Each contruct MUST include the keypair:

key: [membershipHash]: pair: [WakuCredential]

membershipHash

The membershipHash SHOULD be generated by user's participating in a membership group, as decribed in 32/RLN-V1. Each user SHOULD register to the group with an identity_commitment stored in a Merkle tree. A cryptographic hash function that SHOULD be used to generate the membershipHash is SHA256, other hash functions MAY be used. The hash function that is used, SHOULD be mentioned in the verison attribute.

To generate the membershipHash, the treeIndex, membershipContract, chainId and identityCredential attributes SHOULD be used to create a hexadecimal string.

  • it MUST NOT already exist in the keystore.
treeIndex

After a user registers to a group, a treeIndex value of the position in the Merkle tree SHOULD be returned.

  • it MUST be a Merkle tree data structure filled with identity_commitment from user registrations.
  • it MUST be a hexadecimal string
membershipContract

For decentralized membership registrations, the membershipContract SHOULD be a contractAddress from a public blockchain using smart contracts.

  • it MUST be a string.
chainId

It uniquely defines the chain upon which the registration has occurred. The chainId SHOULD be the blockchain identifier used for membershipcontract, as described in EIP155.

  • it MUST be a string
identityCredential

The identityCredential MUST be derived after a succussful decryption of the keystore.

The identityCredential MUST be constructed with the identity_secret, identity_secret_hash, identity_commitment values.

  • it MUST be a hash of identity_commitment stored in a Merkle tree.
  • it MUST be a string.
identity_secret

The identity_secret MUST be constructed with identity_nullifier + identity_trapdoor values.

  • identity_nullifier : Random 32 byte value
  • identity_trapdoor : Random 32 byte value
identity_secret_hash

Used to derive the identity_commitment of the user, and as a private input for zero-knowledge proof generation.

  • it MUST be created with identity_secret as a parameter for the hash function.
  • This secret hash SHOULD be kept private by the user.
identity_commitment
  • it SHOULD be created with identity_secret_hash by using the hash function Poseidon, as described in Poseidon Paper.
  • it MUST be used by a user for group registering.

WakuCredential

The WakuCredential will store values used for encrypting and decrypting user's keystores.

  • it MUST be used for password verification.
  • it MUST follow EIP-2335
  • it SHOULD use SHA256 as the hash function

KDF

The password-based encryption used SHOULD be KDF, key derivation function, to produce a derived key from a password and other parameters. The keystore COULD use PBKDF2 password-based encryption, as described in RFC 2898.

A WakuCredential object MUST include:

Name Description
password used to encrypt keystore and decryption key
secret key to be encrypted
pubKey public key
path HD, hardened derivation, path used to generate the secret
checksum hash function
cipher cipher function

crypto: {
	
	cipher: "string" // The cipher function
	cipherparams: {
		iv: "string" // The cipher parameters
	},
	ciphertext: "string" // The cipher message,
	kdf: "string" // KDF Function,
	kdfparams: {
		param: integer // Salt value and iteration count,
		dklen: integer // Length in octets of derived key, MUST be positive integer,
		c: "string" // Iteration count, MUST be positive integer,
		prf: "string" // Underlying pseudorandom function,
		salt: "string" // Produces a large set of keys based on the password
	},
	mac: "string" // Checksum
}

Decryption

The keystore SHOULD decrypt a user's credentials using a password and the membershipHash, using PBKDF2 that returns the decryptionKey key. The decryption key is used to verify the keystore is correct.

  • To generate the decryptionKey, it MUST be constructed from a password and KDF, as desrcibed in ERC-2335: BLS12-381 Keystore.
  • The decryptionKey, is derived from the cipher function and cipher parameters described in the KDF used in the keystore.

Test Vectors

RLN uses Poseidon hash algorithm to generate the identityCredential, as described in Poseidon Paper. The keystore hash algorithm used is SHA256.

Input:

  • application: "waku-rln-relay"
  • appIdentifier: "01234567890abcdef"
  • version: "0.2"
  • hashFunction: "poseidonHash"
  • password: "sup3rsecure"

identityCredential = {
	IDTrapdoor: [
		211, 23, 66, 42, 179, 130, 131, 111, 201, 205, 244, 34, 27, 238, 244,
        	216, 131, 240, 188, 45, 193, 172, 4, 168, 225, 225, 43, 197, 114, 176,
        	126, 9,
	],
	IDNullifier: [
        	238, 168, 239, 65, 73, 63, 105, 19, 132, 62, 213, 205, 191, 255, 209, 9,
        	178, 155, 239, 201, 131, 125, 233, 136, 246, 217, 9, 237, 55, 89, 81,
        	42,
	],
	IDSecretHash: [
        	150, 54, 194, 28, 18, 216, 138, 253, 95, 139, 120, 109, 98, 129, 146,
        	101, 41, 194, 36, 36, 96, 152, 152, 89, 151, 160, 118, 15, 222, 124,
        	187, 4,
	],
	IDCommitment: [
        	112, 216, 27, 89, 188, 135, 203, 19, 168, 211, 117, 13, 231, 135, 229,
		58, 94, 20, 246, 8, 33, 65, 238, 37, 112, 97, 65, 241, 255, 93, 171, 15,
	],
	
}

membership = {
      chainId: "0xAA36A7",
      treeIndex: 8,
      address: "0x8e1F3742B987d8BA376c0CBbD7357fE1F003ED71",
}

Output:

application: "waku-rln-relay",
appIdentifier: "01234567890abcdef",
version: "0.2",
  credentials: {
    "9DB2B4718A97485B9F70F68D1CC19F4E10F0B4CE943418838E94956CB8E57548": {
      crypto: {
        cipher: "aes-128-ctr",
        cipherparams: {
          iv: "fd6b39eb71d44c59f6bf5ff3d8945c80",
        },
        ciphertext:     "9c72f47ce95de03ed34502d0288e7576b66b51b9e7d5ae882c27bd89f94e6a03c2c44c2ddf0c982e72003d67212105f1b64614f57cabb0ceadab7e07be165eee1121ad6b81951368a9f3be2dd99ea294515f6013d5f2bd4702a40e36cfde2ea298b23b31e5ce719d8040c3331f73d6bf44f88bca39bac0e917d8bf545500e4f40d321c235426a80f315ac70666acbd3bdf803fbc1e7e7103fed466525ed332b25d72b2dbedf6fa383b2305987c1fe276b029570519b3e79930edf08c1029868d05c2c08ab61d7c64f63c054b4f6a5a12d43cdc79751b6fe58d3ed26b69443eb7c9f7efce27912340129c91b6b813ac94efd5776a40b1dda896d61357de208c7c47a14af911cc231355c8093ee6626e89c07e1037f9e0b22c690e3e049014399ca0212c509cb04c71c7860d1b17a0c47711c490c27bad2825926148a1f15a507f36ba2cdaa04897fce2914e53caed0beaf1bebd2a83af76511cc15bff2165ff0860ad6eca1f30022d7739b2a6b6a72f2feeef0f5941183cda015b4631469e1f4cf27003cab9a90920301cb30d95e4554686922dc5a05c13dfb575cdf113c700d607896011970e6ee7d6edb61210ab28ac8f0c84c606c097e3e300f0a5f5341edfd15432bef6225a498726b62a98283829ad51023b2987f30686cfb4ea3951f3957654035ec291f9b0964a3a8665d81b16cec20fb40f944d5f9bf03ac1e444ad45bae3fa85e7465ce620c0966d8148d6e2856f676c4fbbe3ebe470453efb4bbda1866680037917e37765f680e3da96ef3991f3fe5cda80c523996c2234758bf5f7b6d052dc6942f5a92c8b8eec5d2d8940203bbb6b1cba7b7ebc1334334ca69cdb509a5ea58ec6b2ebaea52307589eaae9430eb15ad234c0c39c83accdf3b77e52a616e345209c5bc9b442f9f0fa96836d9342f983a7",
        kdf: "pbkdf2",
        kdfparams: {
          dklen: 32,
          c: 1000000,
          prf: "hmac-sha256",
          salt: "60f0aa92fbf63a8356dfdbed2ab18058",
        },
        mac: "51a227ac6db7f2797c63925880b3db664e034231a4c68daa919ab42d8df38bc6",
      },
    }

Security Considerations

1.) Add a Password

An attacker can identify which credential belongs to a combination of chainId and contractAddress pair by brute forcing the treeIndex iteratively to find a hash match. The RECOMMENDED solution is to add a password to the construction of membershipHash to prevent this attack.

The RECOMMENDED membershipHash Construction:

  • membershipHash SHOULD be constructed with treeIndex, membershipContract, identityCredential, membershipPassword
    • membershipPassword : a new password created to private attacks compromising keystore credentials.
  • The user MUST store the membershipPassword privately.

Copyright and related rights waived via CC0.

References

  1. 32/RLN-V1
  2. 17/WAKU2-RLN-RELAY
  3. SHA256
  4. EIP155
  5. Poseidon Paper
  6. EIP-2335
  7. RFC 2898
  8. ERC-2335: BLS12-381 Keystore