mirror of https://github.com/waku-org/nwaku.git
187 lines
7.0 KiB
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*: 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*: 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
|