nwaku/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim

187 lines
7.0 KiB
Nim

{.push raises: [Defect].}
import
std/[tables, deques],
options, chronos, stint,
web3,
eth/keys,
libp2p/protobuf/minprotobuf,
stew/arrayops,
waku_rln_relay_constants,
../../utils/protobuf
when defined(rln) or (not defined(rln) and not defined(rlnzerokit)):
## Bn256 and RLN are Nim wrappers for the data types used in
## the rln library https://github.com/kilic/rln/blob/3bbec368a4adc68cd5f9bfae80b17e1bbb4ef373/src/ffi.rs
type Bn256* = pointer
type RLN*[E] = pointer
type RLNResult* = Result[RLN[Bn256], string]
when defined(rlnzerokit):
## RLN is a Nim wrapper for the data types used in zerokit RLN
type RLN* {.incompleteStruct.} = object
type RLNResult* = Result[ptr RLN, string]
type RlnRelayResult*[T] = Result[T, string]
type
# identity key as defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
IDKey* = array[32, byte]
# hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
IDCommitment* = array[32, byte]
MerkleNode* = array[32, byte] # Each node of the Merkle tee is a Poseidon hash which is a 32 byte value
Nullifier* = array[32, byte]
Epoch* = array[32, byte]
RlnIdentifier* = array[32, byte]
when defined(rln) or (not defined(rln) and not defined(rlnzerokit)):
type
ZKSNARK* = array[256, byte]
when defined(rlnzerokit):
type
ZKSNARK* = array[128, byte]
# Custom data types defined for waku rln relay -------------------------
type MembershipKeyPair* = object
## user's identity key (a secret key) which is selected randomly
## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
idKey*: IDKey
# hash of user's identity key generated by
# Poseidon hash function implemented in rln lib
# more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
idCommitment*: IDCommitment
type RateLimitProof* = object
## RateLimitProof holds the public inputs to rln circuit as
## defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs
## the `proof` field carries the actual zkSNARK proof
proof*: ZKSNARK
## the root of Merkle tree used for the generation of the `proof`
merkleRoot*: MerkleNode
## the epoch used for the generation of the `proof`
epoch*: Epoch
## shareX and shareY are shares of user's identity key
## these shares are created using Shamir secret sharing scheme
## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Linear-Equation-amp-SSS
shareX*: MerkleNode
shareY*: MerkleNode
## nullifier enables linking two messages published during the same epoch
## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Nullifiers
nullifier*: Nullifier
## Application specific RLN Identifier
rlnIdentifier*: RlnIdentifier
type MembershipIndex* = uint
type RlnMembershipCredentials* = object
membershipKeyPair*: MembershipKeyPair
rlnIndex*: MembershipIndex
type ProofMetadata* = object
nullifier*: Nullifier
shareX*: MerkleNode
shareY*: MerkleNode
when defined(rln) or (not defined(rln) and not defined(rlnzerokit)):
type WakuRLNRelay* = ref object
membershipKeyPair*: MembershipKeyPair
# membershipIndex denotes the index of a leaf in the Merkle tree
# that contains the pk of the current peer
# this index is used to retrieve the peer's authentication path
membershipIndex*: MembershipIndex
membershipContractAddress*: Address
ethClientAddress*: string
ethAccountAddress*: Option[Address]
# this field is required for signing transactions
# TODO may need to erase this ethAccountPrivateKey when is not used
# TODO may need to make ethAccountPrivateKey mandatory
ethAccountPrivateKey*: Option[PrivateKey]
rlnInstance*: RLN[Bn256]
pubsubTopic*: string # the pubsub topic for which rln relay is mounted
# contentTopic should be of type waku_message.ContentTopic, however, due to recursive module dependency, the underlying type of ContentTopic is used instead
# TODO a long-term solution is to place types with recursive dependency inside one file
contentTopic*: string
# the log of nullifiers and Shamir shares of the past messages grouped per epoch
nullifierLog*: Table[Epoch, seq[ProofMetadata]]
lastEpoch*: Epoch # the epoch of the last published rln message
validMerkleRoots*: Deque[MerkleNode] # An array of valid merkle roots, which are updated in a FIFO fashion
when defined(rlnzerokit):
type WakuRLNRelay* = ref object
membershipKeyPair*: MembershipKeyPair
# membershipIndex denotes the index of a leaf in the Merkle tree
# that contains the pk of the current peer
# this index is used to retrieve the peer's authentication path
membershipIndex*: MembershipIndex
membershipContractAddress*: Address
ethClientAddress*: string
ethAccountAddress*: Option[Address]
# this field is required for signing transactions
# TODO may need to erase this ethAccountPrivateKey when is not used
# TODO may need to make ethAccountPrivateKey mandatory
ethAccountPrivateKey*: Option[PrivateKey]
rlnInstance*: ptr RLN
pubsubTopic*: string # the pubsub topic for which rln relay is mounted
# contentTopic should be of type waku_message.ContentTopic, however, due to recursive module dependency, the underlying type of ContentTopic is used instead
# TODO a long-term solution is to place types with recursive dependency inside one file
contentTopic*: string
# the log of nullifiers and Shamir shares of the past messages grouped per epoch
nullifierLog*: Table[Epoch, seq[ProofMetadata]]
lastEpoch*: Epoch # the epoch of the last published rln message
validMerkleRoots*: Deque[MerkleNode] # An array of valid merkle roots, which are updated in a FIFO fashion
type MessageValidationResult* {.pure.} = enum
Valid, Invalid, Spam
# Protobufs enc and init
proc init*(T: type RateLimitProof, buffer: seq[byte]): ProtoResult[T] =
var nsp: RateLimitProof
let pb = initProtoBuffer(buffer)
var proof: seq[byte]
discard ? pb.getField(1, proof)
discard nsp.proof.copyFrom(proof)
var merkleRoot: seq[byte]
discard ? pb.getField(2, merkleRoot)
discard nsp.merkleRoot.copyFrom(merkleRoot)
var epoch: seq[byte]
discard ? pb.getField(3, epoch)
discard nsp.epoch.copyFrom(epoch)
var shareX: seq[byte]
discard ? pb.getField(4, shareX)
discard nsp.shareX.copyFrom(shareX)
var shareY: seq[byte]
discard ? pb.getField(5, shareY)
discard nsp.shareY.copyFrom(shareY)
var nullifier: seq[byte]
discard ? pb.getField(6, nullifier)
discard nsp.nullifier.copyFrom(nullifier)
var rlnIdentifier: seq[byte]
discard ? pb.getField(7, rlnIdentifier)
discard nsp.rlnIdentifier.copyFrom(rlnIdentifier)
return ok(nsp)
proc encode*(nsp: RateLimitProof): ProtoBuffer =
var output = initProtoBuffer()
output.write3(1, nsp.proof)
output.write3(2, nsp.merkleRoot)
output.write3(3, nsp.epoch)
output.write3(4, nsp.shareX)
output.write3(5, nsp.shareY)
output.write3(6, nsp.nullifier)
output.write3(7, nsp.rlnIdentifier)
output.finish3()
return output