feat: stateless RLN ( bump v0.9.0 ) (#3621)

This commit is contained in:
Darshan K 2025-10-15 19:08:46 +05:30 committed by GitHub
parent 7e5041d5e1
commit deebee45d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 68 additions and 381 deletions

View File

@ -177,7 +177,7 @@ nimbus-build-system-nimble-dir:
.PHONY: librln
LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit
LIBRLN_VERSION := v0.8.0
LIBRLN_VERSION := v0.9.0
ifeq ($(detected_OS),Windows)
LIBRLN_FILE := rln.lib

View File

@ -15,7 +15,7 @@ proc benchmark(
manager: OnChainGroupManager, registerCount: int, messageLimit: int
): Future[string] {.async, gcsafe.} =
# Register a new member so that we can later generate proofs
let idCredentials = generateCredentials(manager.rlnInstance, registerCount)
let idCredentials = generateCredentials(registerCount)
var start_time = getTime()
for i in 0 .. registerCount - 1:

View File

@ -49,6 +49,6 @@ else
exit 1
fi
# if submodule version = version in Makefile, build rln
cargo build --release -p rln --manifest-path "${build_dir}/rln/Cargo.toml" --features arkzkey
cargo build --release -p rln --manifest-path "${build_dir}/rln/Cargo.toml"
cp "${build_dir}/target/release/librln.a" "${output_filename}"
fi

View File

@ -151,7 +151,7 @@ suite "RLN Proofs as a Lightpush Service":
client.mountLegacyLightPushClient()
let manager1 = cast[OnchainGroupManager](server.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))

View File

@ -151,7 +151,7 @@ suite "RLN Proofs as a Lightpush Service":
client.mountLightPushClient()
let manager1 = cast[OnchainGroupManager](server.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))

View File

@ -34,14 +34,9 @@ proc valid(x: seq[byte]): bool =
return true
suite "membershipKeyGen":
var rlnRes {.threadvar.}: RLNResult
setup:
rlnRes = createRLNInstanceWrapper()
test "ok":
# Given we generate valid membership keys
let identityCredentialsRes = membershipKeyGen(rlnRes.get())
let identityCredentialsRes = membershipKeyGen()
# Then it contains valid identity credentials
let identityCredentials = identityCredentialsRes.get()
@ -62,7 +57,7 @@ suite "membershipKeyGen":
keyGenMock
# When we generate the membership keys
let identityCredentialsRes = membershipKeyGen(rlnRes.get())
let identityCredentialsRes = membershipKeyGen()
# Then it fails
check:
@ -85,7 +80,7 @@ suite "membershipKeyGen":
keyGenMock
# When we generate the membership keys
let identityCredentialsRes = membershipKeyGen(rlnRes.get())
let identityCredentialsRes = membershipKeyGen()
# Then it fails
check:

View File

@ -60,44 +60,6 @@ suite "Onchain group manager":
(waitFor manager.init()).isOkOr:
raiseAssert $error
test "should error on initialization when loaded metadata does not match":
(waitFor manager.init()).isOkOr:
assert false, $error
let metadataSetRes = manager.setMetadata()
assert metadataSetRes.isOk(), metadataSetRes.error
let metadataOpt = manager.rlnInstance.getMetadata().valueOr:
assert false, $error
return
assert metadataOpt.isSome(), "metadata is not set"
let metadata = metadataOpt.get()
assert metadata.chainId == 1234, "chainId is not equal to 1234"
assert metadata.contractAddress == manager.ethContractAddress,
"contractAddress is not equal to " & manager.ethContractAddress
let web3 = manager.ethRpc.get()
let accounts = waitFor web3.provider.eth_accounts()
web3.defaultAccount = accounts[2]
let (privateKey, acc) = createEthAccount(web3)
let tokenAddress = (waitFor deployTestToken(privateKey, acc, web3)).valueOr:
assert false, "Failed to deploy test token contract: " & $error
return
let differentContractAddress = (
waitFor executeForgeContractDeployScripts(privateKey, acc, web3)
).valueOr:
assert false, "Failed to deploy RLN contract: " & $error
return
# simulating a change in the contractAddress
let manager2 = OnchainGroupManager(
ethClientUrls: @[EthClient],
ethContractAddress: $differentContractAddress,
rlnInstance: manager.rlnInstance,
onFatalErrorAction: proc(errStr: string) =
assert false, errStr
,
)
let e = waitFor manager2.init()
(e).isErrOr:
assert false, "Expected error when contract address doesn't match"
test "should error if contract does not exist":
manager.ethContractAddress = "0x0000000000000000000000000000000000000000"
@ -118,7 +80,7 @@ suite "Onchain group manager":
check getCurrentExceptionMsg().len == 38
test "trackRootChanges: should sync to the state of the group":
let credentials = generateCredentials(manager.rlnInstance)
let credentials = generateCredentials()
(waitFor manager.init()).isOkOr:
raiseAssert $error
@ -133,17 +95,7 @@ suite "Onchain group manager":
let merkleRootAfter = waitFor manager.fetchMerkleRoot()
let metadataSetRes = manager.setMetadata()
assert metadataSetRes.isOk(), metadataSetRes.error
let metadataOpt = getMetadata(manager.rlnInstance).valueOr:
raiseAssert $error
assert metadataOpt.isSome(), "metadata is not set"
let metadata = metadataOpt.get()
check:
metadata.validRoots == manager.validRoots.toSeq()
merkleRootBefore != merkleRootAfter
test "trackRootChanges: should fetch history correctly":
@ -152,7 +104,7 @@ suite "Onchain group manager":
# so we can't use it in this test.
const credentialCount = 6
let credentials = generateCredentials(manager.rlnInstance, credentialCount)
let credentials = generateCredentials(credentialCount)
(waitFor manager.init()).isOkOr:
raiseAssert $error
@ -191,7 +143,7 @@ suite "Onchain group manager":
(waitFor manager.init()).isOkOr:
raiseAssert $error
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
let merkleRootBefore = waitFor manager.fetchMerkleRoot()
try:
@ -207,7 +159,7 @@ suite "Onchain group manager":
manager.latestIndex == 1
test "register: callback is called":
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
let idCommitment = idCredentials.idCommitment
let fut = newFuture[void]()
@ -237,7 +189,7 @@ suite "Onchain group manager":
waitFor fut
test "withdraw: should guard against uninitialized state":
let idSecretHash = generateCredentials(manager.rlnInstance).idSecretHash
let idSecretHash = generateCredentials().idSecretHash
try:
waitFor manager.withdraw(idSecretHash)
@ -247,7 +199,7 @@ suite "Onchain group manager":
assert false, "exception raised: " & getCurrentExceptionMsg()
test "validateRoot: should validate good root":
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
let idCommitment = idCredentials.idCommitment
let fut = newFuture[void]()
@ -298,7 +250,7 @@ suite "Onchain group manager":
validated
test "validateRoot: should reject bad root":
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
let idCommitment = idCredentials.idCommitment
(waitFor manager.init()).isOkOr:
@ -331,7 +283,7 @@ suite "Onchain group manager":
validated == false
test "verifyProof: should verify valid proof":
let credentials = generateCredentials(manager.rlnInstance)
let credentials = generateCredentials()
(waitFor manager.init()).isOkOr:
raiseAssert $error
@ -383,7 +335,7 @@ suite "Onchain group manager":
(waitFor manager.init()).isOkOr:
raiseAssert $error
let idCredential = generateCredentials(manager.rlnInstance)
let idCredential = generateCredentials()
try:
waitFor manager.register(idCredential, UserMessageLimit(20))
@ -420,7 +372,7 @@ suite "Onchain group manager":
test "root queue should be updated correctly":
const credentialCount = 12
let credentials = generateCredentials(manager.rlnInstance, credentialCount)
let credentials = generateCredentials(credentialCount)
(waitFor manager.init()).isOkOr:
raiseAssert $error

View File

@ -36,15 +36,11 @@ suite "Waku rln relay":
test "key_gen Nim Wrappers":
let merkleDepth: csize_t = 20
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
# keysBufferPtr will hold the generated identity credential i.e., id trapdoor, nullifier, secret hash and commitment
var keysBuffer: Buffer
let
keysBufferPtr = addr(keysBuffer)
done = key_gen(rlnInstance.get(), keysBufferPtr)
done = key_gen(keysBufferPtr, true)
require:
# check whether the keys are generated successfully
done
@ -56,12 +52,7 @@ suite "Waku rln relay":
info "generated keys: ", generatedKeys
test "membership Key Generation":
# create an RLN instance
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
let idCredentialsRes = membershipKeyGen(rlnInstance.get())
let idCredentialsRes = membershipKeyGen()
require:
idCredentialsRes.isOk()
@ -79,61 +70,6 @@ suite "Waku rln relay":
info "the generated identity credential: ", idCredential
test "setMetadata rln utils":
# create an RLN instance which also includes an empty Merkle tree
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
let rln = rlnInstance.get()
check:
rln
.setMetadata(
RlnMetadata(
lastProcessedBlock: 128,
chainId: 1155511'u256,
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155",
)
)
.isOk()
test "getMetadata rln utils":
# create an RLN instance which also includes an empty Merkle tree
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
let rln = rlnInstance.get()
require:
rln
.setMetadata(
RlnMetadata(
lastProcessedBlock: 128,
chainId: 1155511'u256,
contractAddress: "0x9c09146844c1326c2dbc41c451766c7138f88155",
)
)
.isOk()
let metadataOpt = rln.getMetadata().valueOr:
raiseAssert $error
assert metadataOpt.isSome(), "metadata is not set"
let metadata = metadataOpt.get()
check:
metadata.lastProcessedBlock == 128
metadata.chainId == 1155511'u256
metadata.contractAddress == "0x9c09146844c1326c2dbc41c451766c7138f88155"
test "getMetadata: empty rln metadata":
# create an RLN instance which also includes an empty Merkle tree
let rln = createRLNInstanceWrapper().valueOr:
raiseAssert $error
let metadata = rln.getMetadata().valueOr:
raiseAssert $error
check:
metadata.isNone()
test "hash Nim Wrappers":
# create an RLN instance
let rlnInstance = createRLNInstanceWrapper()
@ -149,7 +85,7 @@ suite "Waku rln relay":
# prepare other inputs to the hash function
let outputBuffer = default(Buffer)
let hashSuccess = sha256(unsafeAddr hashInputBuffer, unsafeAddr outputBuffer)
let hashSuccess = sha256(unsafeAddr hashInputBuffer, unsafeAddr outputBuffer, true)
require:
hashSuccess
let outputArr = cast[ptr array[32, byte]](outputBuffer.`ptr`)[]
@ -348,7 +284,7 @@ suite "Waku rln relay":
raiseAssert $error
let manager = cast[OnchainGroupManager](wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -405,7 +341,7 @@ suite "Waku rln relay":
raiseAssert $error
let manager = cast[OnchainGroupManager](wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -455,7 +391,7 @@ suite "Waku rln relay":
raiseAssert "failed to create waku rln relay: " & $error
let manager1 = cast[OnchainGroupManager](wakuRlnRelay1.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))
@ -469,7 +405,7 @@ suite "Waku rln relay":
raiseAssert "failed to create waku rln relay: " & $error
let manager2 = cast[OnchainGroupManager](wakuRlnRelay2.groupManager)
let idCredentials2 = generateCredentials(manager2.rlnInstance)
let idCredentials2 = generateCredentials()
try:
waitFor manager2.register(idCredentials2, UserMessageLimit(20))
@ -502,15 +438,7 @@ suite "Waku rln relay":
msgValidate2 == MessageValidationResult.Valid
test "toIDCommitment and toUInt256":
# create an instance of rln
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
let rln = rlnInstance.get()
# create an idendity credential
let idCredentialRes = rln.membershipKeyGen()
let idCredentialRes = membershipKeyGen()
require:
idCredentialRes.isOk()
@ -526,12 +454,7 @@ suite "Waku rln relay":
idCredential.idCommitment == idCommitment
test "Read/Write RLN credentials":
# create an RLN instance
let rlnInstance = createRLNInstanceWrapper()
require:
rlnInstance.isOk()
let idCredentialRes = membershipKeyGen(rlnInstance.get())
let idCredentialRes = membershipKeyGen()
require:
idCredentialRes.isOk()

View File

@ -63,7 +63,7 @@ procSuite "WakuNode - RLN relay":
# Registration is mandatory before sending messages with rln-relay
let manager1 = cast[OnchainGroupManager](node1.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))
@ -180,7 +180,7 @@ procSuite "WakuNode - RLN relay":
await node.mountRlnRelay(wakuRlnConfig)
await node.start()
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -299,7 +299,7 @@ procSuite "WakuNode - RLN relay":
await node1.start()
let manager1 = cast[OnchainGroupManager](node1.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))
@ -416,7 +416,7 @@ procSuite "WakuNode - RLN relay":
# Registration is mandatory before sending messages with rln-relay
let manager1 = cast[OnchainGroupManager](node1.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))
@ -583,7 +583,7 @@ procSuite "WakuNode - RLN relay":
# Registration is mandatory before sending messages with rln-relay
let manager1 = cast[OnchainGroupManager](node1.wakuRlnRelay.groupManager)
let idCredentials1 = generateCredentials(manager1.rlnInstance)
let idCredentials1 = generateCredentials()
try:
waitFor manager1.register(idCredentials1, UserMessageLimit(20))

View File

@ -44,8 +44,8 @@ func strip0xPrefix(s: string): string =
else:
s
proc generateCredentials*(rlnInstance: ptr RLN): IdentityCredential =
let credRes = membershipKeyGen(rlnInstance)
proc generateCredentials*(): IdentityCredential =
let credRes = membershipKeyGen()
return credRes.get()
proc getRateCommitment*(
@ -55,10 +55,10 @@ proc getRateCommitment*(
idCommitment: idCredential.idCommitment, userMessageLimit: userMessageLimit
).toLeaf()
proc generateCredentials*(rlnInstance: ptr RLN, n: int): seq[IdentityCredential] =
proc generateCredentials*(n: int): seq[IdentityCredential] =
var credentials: seq[IdentityCredential]
for i in 0 ..< n:
credentials.add(generateCredentials(rlnInstance))
credentials.add(generateCredentials())
return credentials
proc getContractAddressFromDeployScriptOutput(output: string): Result[string, string] =

View File

@ -265,7 +265,7 @@ suite "Waku v2 Rest API - Relay":
await node.start()
# Registration is mandatory before sending messages with rln-relay
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -516,7 +516,7 @@ suite "Waku v2 Rest API - Relay":
await node.start()
# Registration is mandatory before sending messages with rln-relay
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -588,7 +588,7 @@ suite "Waku v2 Rest API - Relay":
# Registration is mandatory before sending messages with rln-relay
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -650,7 +650,7 @@ suite "Waku v2 Rest API - Relay":
# Registration is mandatory before sending messages with rln-relay
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))
@ -725,7 +725,7 @@ suite "Waku v2 Rest API - Relay":
# Registration is mandatory before sending messages with rln-relay
let manager = cast[OnchainGroupManager](node.wakuRlnRelay.groupManager)
let idCredentials = generateCredentials(manager.rlnInstance)
let idCredentials = generateCredentials()
try:
waitFor manager.register(idCredentials, UserMessageLimit(20))

View File

@ -30,16 +30,8 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) =
# 1. load configuration
trace "configuration", conf = $conf
# 2. initialize rlnInstance
let rlnInstanceRes = createRLNInstance(d = 20)
if rlnInstanceRes.isErr():
error "failure while creating RLN instance", error = rlnInstanceRes.error
quit(1)
let rlnInstance = rlnInstanceRes.get()
# 3. generate credentials
let credentialRes = rlnInstance.membershipKeyGen()
# 2. generate credentials
let credentialRes = membershipKeyGen()
if credentialRes.isErr():
error "failure while generating credentials", error = credentialRes.error
quit(1)
@ -61,12 +53,11 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) =
error "Unrecoverable error occurred", error = msg
quit(QuitFailure)
# 4. initialize OnchainGroupManager
# 3. initialize OnchainGroupManager
let groupManager = OnchainGroupManager(
ethClientUrls: conf.ethClientUrls,
chainId: conf.chainId,
ethContractAddress: conf.ethContractAddress,
rlnInstance: rlnInstance,
keystorePath: none(string),
keystorePassword: none(string),
ethPrivateKey: some(conf.ethPrivateKey),
@ -82,7 +73,7 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) =
error = getCurrentExceptionMsg()
quit(1)
# 5. register on-chain
# 4. register on-chain
try:
waitFor groupManager.register(credential, conf.userMessageLimit)
except Exception, CatchableError:
@ -98,7 +89,7 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) =
membershipIndex = groupManager.membershipIndex.get()
info "Your user message limit is", userMessageLimit = conf.userMessageLimit
# 6. write to keystore
# 5. write to keystore
let keystoreCred = KeystoreMembership(
membershipContract: MembershipContract(
chainId: $groupManager.chainId, address: conf.ethContractAddress

2
vendor/zerokit vendored

@ -1 +1 @@
Subproject commit dc0b31752c91e7b4fefc441cfa6a8210ad7dba7b
Subproject commit a4bb3feb5054e6fd24827adf204493e6e173437b

View File

@ -144,25 +144,6 @@ proc fetchMaxMembershipRateLimit*(
error "Failed to fetch max membership rate limit", error = getCurrentExceptionMsg()
return err("Failed to fetch max membership rate limit: " & getCurrentExceptionMsg())
proc setMetadata*(
g: OnchainGroupManager, lastProcessedBlock = none(BlockNumber)
): GroupManagerResult[void] =
let normalizedBlock = lastProcessedBlock.get(g.latestProcessedBlock)
try:
let metadataSetRes = g.rlnInstance.setMetadata(
RlnMetadata(
lastProcessedBlock: normalizedBlock.uint64,
chainId: g.chainId,
contractAddress: g.ethContractAddress,
validRoots: g.validRoots.toSeq(),
)
)
if metadataSetRes.isErr():
return err("failed to persist rln metadata: " & metadataSetRes.error)
except CatchableError:
return err("failed to persist rln metadata: " & getCurrentExceptionMsg())
return ok()
template initializedGuard(g: OnchainGroupManager): untyped =
if not g.initialized:
raise newException(CatchableError, "OnchainGroupManager is not initialized")
@ -593,18 +574,6 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.}
g.idCredentials = some(keystoreCred.identityCredential)
let metadataGetOptRes = g.rlnInstance.getMetadata()
if metadataGetOptRes.isErr():
warn "could not initialize with persisted rln metadata"
elif metadataGetOptRes.get().isSome():
let metadata = metadataGetOptRes.get().get()
if metadata.chainId != g.chainId:
return err(
fmt"chain id mismatch. persisted={metadata.chainId}, smart_contract_chainId={g.chainId}"
)
if metadata.contractAddress != g.ethContractAddress.toLower():
return err("persisted data: contract address mismatch")
let maxMembershipRateLimitRes = await g.fetchMaxMembershipRateLimit()
let maxMembershipRateLimit = maxMembershipRateLimitRes.valueOr:
return err("failed to fetch max membership rate limit: " & error)
@ -631,9 +600,6 @@ method stop*(g: OnchainGroupManager): Future[void] {.async, gcsafe.} =
if g.ethRpc.isSome():
g.ethRpc.get().ondisconnect = nil
await g.ethRpc.get().close()
let flushed = g.rlnInstance.flush()
if not flushed:
error "failed to flush to the tree db"
g.initialized = false

View File

@ -23,7 +23,7 @@ proc toBuffer*(x: openArray[byte]): Buffer =
#-------------------------------- zkSNARKs operations -----------------------------------------
proc key_gen*(
ctx: ptr RLN, output_buffer: ptr Buffer
output_buffer: ptr Buffer, is_little_endian: bool
): bool {.importc: "extended_key_gen".}
## generates identity trapdoor, identity nullifier, identity secret hash and id commitment tuple serialized inside output_buffer as | identity_trapdoor<32> | identity_nullifier<32> | identity_secret_hash<32> | id_commitment<32> |
@ -32,7 +32,7 @@ proc key_gen*(
## the return bool value indicates the success or failure of the operation
proc seeded_key_gen*(
ctx: ptr RLN, input_buffer: ptr Buffer, output_buffer: ptr Buffer
input_buffer: ptr Buffer, output_buffer: ptr Buffer, is_little_endian: bool
): bool {.importc: "seeded_extended_key_gen".}
## generates identity trapdoor, identity nullifier, identity secret hash and id commitment tuple serialized inside output_buffer as | identity_trapdoor<32> | identity_nullifier<32> | identity_secret_hash<32> | id_commitment<32> | using ChaCha20
@ -40,6 +40,7 @@ proc seeded_key_gen*(
## The input seed provided by the user is hashed using Keccak256 before being passed to ChaCha20 as seed.
## identity secret hash is the poseidon hash of [identity_trapdoor, identity_nullifier]
## id commitment is the poseidon hash of the identity secret hash
# use_little_endian: if true, uses big or little endian for serialization (default: true)
## the return bool value indicates the success or failure of the operation
proc generate_proof*(
@ -120,39 +121,34 @@ proc zk_verify*(
## the verification of the zk proof is available in proof_is_valid_ptr, where a value of true indicates success and false a failure
## the return bool value indicates the success or failure of the operation
#----------------------------------------------------------------------------------------------
#-------------------------------- Common procedures -------------------------------------------
# stateful version
proc new_circuit*(
tree_height: uint, input_buffer: ptr Buffer, ctx: ptr (ptr RLN)
tree_depth: uint, input_buffer: ptr Buffer, ctx: ptr (ptr RLN)
): bool {.importc: "new".}
## creates an instance of rln object as defined by the zerokit RLN lib
## tree_height represent the depth of the Merkle tree
## input_buffer contains a serialization of the path where the circuit resources can be found (.r1cs, .wasm, .zkey and optionally the verification_key.json)
## ctx holds the final created rln object
## the return bool value indicates the success or failure of the operation
# stateless version
proc new_circuit*(ctx: ptr (ptr RLN)): bool {.importc: "new".}
proc new_circuit_from_data*(
tree_height: uint,
circom_buffer: ptr Buffer,
zkey_buffer: ptr Buffer,
vk_buffer: ptr Buffer,
ctx: ptr (ptr RLN),
zkey_buffer: ptr Buffer, graph_buffer: ptr Buffer, ctx: ptr (ptr RLN)
): bool {.importc: "new_with_params".}
## creates an instance of rln object as defined by the zerokit RLN lib by passing the required inputs as byte arrays
## tree_height represent the depth of the Merkle tree
## circom_buffer contains the bytes read from the Circom .wasm circuit
## zkey_buffer contains the bytes read from the .zkey proving key
## vk_buffer contains the bytes read from the verification_key.json
## graph_buffer contains the bytes read from the graph data file
## ctx holds the final created rln object
## the return bool value indicates the success or failure of the operation
#-------------------------------- Hashing utils -------------------------------------------
proc sha256*(
input_buffer: ptr Buffer, output_buffer: ptr Buffer
input_buffer: ptr Buffer, output_buffer: ptr Buffer, is_little_endian: bool
): bool {.importc: "hash".}
## it hashes (sha256) the plain text supplied in inputs_buffer and then maps it to a field element
@ -162,7 +158,7 @@ proc sha256*(
## the output_buffer contains 32 bytes hash output
proc poseidon*(
input_buffer: ptr Buffer, output_buffer: ptr Buffer
input_buffer: ptr Buffer, output_buffer: ptr Buffer, is_little_endian: bool
): bool {.importc: "poseidon_hash".}
## it hashes (poseidon) the plain text supplied in inputs_buffer
@ -170,27 +166,3 @@ proc poseidon*(
## inputs_buffer holds the hash input as a byte seq
## the hash output is generated and populated inside output_buffer
## the output_buffer contains 32 bytes hash output
#-------------------------------- Persistent Metadata utils -------------------------------------------
proc set_metadata*(
ctx: ptr RLN, input_buffer: ptr Buffer
): bool {.importc: "set_metadata".}
## sets the metadata stored by ctx to the value passed by input_buffer
## the input_buffer holds a serialized representation of the metadata (format to be defined)
## input_buffer holds the metadata as a byte seq
## the return bool value indicates the success or failure of the operation
proc get_metadata*(
ctx: ptr RLN, output_buffer: ptr Buffer
): bool {.importc: "get_metadata".}
## gets the metadata stored by ctx and populates the passed pointer output_buffer with it
## the output_buffer holds the metadata as a byte seq
## the return bool value indicates the success or failure of the operation
proc flush*(ctx: ptr RLN): bool {.importc: "flush".}
## flushes the write buffer to the database
## the return bool value indicates the success or failure of the operation
## This allows more robust and graceful handling of the database connection

View File

@ -14,7 +14,7 @@ import ../../waku_core, ../../waku_keystore
logScope:
topics = "waku rln_relay ffi"
proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[IdentityCredential] =
proc membershipKeyGen*(): RlnRelayResult[IdentityCredential] =
## generates a IdentityCredential that can be used for the registration into the rln membership contract
## Returns an error if the key generation fails
@ -22,7 +22,7 @@ proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[IdentityCredential] =
var
keysBuffer: Buffer
keysBufferPtr = addr(keysBuffer)
done = key_gen(ctxPtr, keysBufferPtr)
done = key_gen(keysBufferPtr, true)
# check whether the keys are generated successfully
if (done == false):
@ -80,14 +80,13 @@ proc `%`(c: RlnConfig): JsonNode =
}
return %[("resources_folder", %c.resources_folder), ("tree_config", %tree_config)]
proc createRLNInstanceLocal(d = MerkleTreeDepth): RLNResult =
proc createRLNInstanceLocal(): RLNResult =
## generates an instance of RLN
## An RLN instance supports both zkSNARKs logics and Merkle tree data structure and operations
## d indicates the depth of Merkle tree
## Returns an error if the instance creation fails
let rln_config = RlnConfig(
resources_folder: "tree_height_" & $d & "/",
resources_folder: "tree_height_/",
tree_config: RlnTreeConfig(
cache_capacity: 15_000,
mode: "high_throughput",
@ -100,7 +99,7 @@ proc createRLNInstanceLocal(d = MerkleTreeDepth): RLNResult =
var
rlnInstance: ptr RLN
merkleDepth: csize_t = uint(d)
merkleDepth: csize_t = uint(20)
configBuffer =
serialized_rln_config.toOpenArrayByte(0, serialized_rln_config.high).toBuffer()
@ -112,12 +111,12 @@ proc createRLNInstanceLocal(d = MerkleTreeDepth): RLNResult =
return err("error in parameters generation")
return ok(rlnInstance)
proc createRLNInstance*(d = MerkleTreeDepth): RLNResult =
proc createRLNInstance*(): RLNResult =
## Wraps the rln instance creation for metrics
## Returns an error if the instance creation fails
var res: RLNResult
waku_rln_instance_creation_duration_seconds.nanosecondTime:
res = createRLNInstanceLocal(d)
res = createRLNInstanceLocal()
return res
proc sha256*(data: openArray[byte]): RlnRelayResult[MerkleNode] =
@ -128,7 +127,7 @@ proc sha256*(data: openArray[byte]): RlnRelayResult[MerkleNode] =
outputBuffer: Buffer # will holds the hash output
trace "sha256 hash input buffer length", bufflen = hashInputBuffer.len
let hashSuccess = sha256(addr hashInputBuffer, addr outputBuffer)
let hashSuccess = sha256(addr hashInputBuffer, addr outputBuffer, true)
# check whether the hash call is done successfully
if not hashSuccess:
@ -145,7 +144,7 @@ proc poseidon*(data: seq[seq[byte]]): RlnRelayResult[array[32, byte]] =
hashInputBuffer = inputBytes.toBuffer()
outputBuffer: Buffer # will holds the hash output
let hashSuccess = poseidon(addr hashInputBuffer, addr outputBuffer)
let hashSuccess = poseidon(addr hashInputBuffer, addr outputBuffer, true)
# check whether the hash call is done successfully
if not hashSuccess:
@ -192,114 +191,3 @@ proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] =
externalNullifier: externalNullifier,
)
)
type RlnMetadata* = object
lastProcessedBlock*: uint64
chainId*: UInt256
contractAddress*: string
validRoots*: seq[MerkleNode]
proc serialize(metadata: RlnMetadata): seq[byte] =
## serializes the metadata
## returns the serialized metadata
return concat(
@(metadata.lastProcessedBlock.toBytes()),
@(metadata.chainId.toBytes(Endianness.littleEndian)[0 .. 7]),
@(hexToSeqByte(toLower(metadata.contractAddress))),
@(uint64(metadata.validRoots.len()).toBytes()),
@(serialize(metadata.validRoots)),
)
type MerkleNodeSeq = seq[MerkleNode]
proc deserialize(T: type MerkleNodeSeq, merkleNodeByteSeq: seq[byte]): T =
## deserializes a byte seq to a seq of MerkleNodes
## the order of serialization is |merkle_node_len<8>|merkle_node[len]|
var roots = newSeq[MerkleNode]()
let len = uint64.fromBytes(merkleNodeByteSeq[0 .. 7], Endianness.littleEndian)
trace "length of valid roots", len
for i in 0'u64 ..< len:
# convert seq[byte] to array[32, byte]
let fromByte = 8 + i * 32
let toByte = fromByte + 31
let rawRoot = merkleNodeByteSeq[fromByte .. toByte]
trace "raw root", rawRoot = rawRoot
var root: MerkleNode
discard root.copyFrom(rawRoot)
roots.add(root)
return roots
proc setMetadata*(rlnInstance: ptr RLN, metadata: RlnMetadata): RlnRelayResult[void] =
## sets the metadata of the RLN instance
## returns an error if the metadata could not be set
## returns void if the metadata is set successfully
# serialize the metadata
let metadataBytes = serialize(metadata)
trace "setting metadata",
metadata = metadata, metadataBytes = metadataBytes, len = metadataBytes.len
var metadataBuffer = metadataBytes.toBuffer()
let metadataBufferPtr = addr metadataBuffer
# set the metadata
let metadataSet = set_metadata(rlnInstance, metadataBufferPtr)
if not metadataSet:
return err("could not set the metadata")
return ok()
proc getMetadata*(rlnInstance: ptr RLN): RlnRelayResult[Option[RlnMetadata]] =
## gets the metadata of the RLN instance
## returns an error if the metadata could not be retrieved
## returns the metadata if the metadata is retrieved successfully
# read the metadata
var
metadata {.noinit.}: Buffer = Buffer()
metadataPtr = addr(metadata)
getMetadataSuccessful = get_metadata(rlnInstance, metadataPtr)
if not getMetadataSuccessful:
return err("could not get the metadata")
trace "metadata length", metadataLen = metadata.len
if metadata.len == 0:
return ok(none(RlnMetadata))
let
lastProcessedBlockOffset = 0
chainIdOffset = lastProcessedBlockOffset + 8
contractAddressOffset = chainIdOffset + 8
validRootsOffset = contractAddressOffset + 20
var
lastProcessedBlock: uint64
chainId: UInt256
contractAddress: string
validRoots: MerkleNodeSeq
# 8 + 8 + 20 + 8 + (5*32) = 204
var metadataBytes = cast[ptr array[204, byte]](metadata.`ptr`)[]
trace "received metadata bytes",
metadataBytes = metadataBytes, len = metadataBytes.len
lastProcessedBlock =
uint64.fromBytes(metadataBytes[lastProcessedBlockOffset .. chainIdOffset - 1])
chainId = UInt256.fromBytes(
metadataBytes[chainIdOffset .. contractAddressOffset - 1], Endianness.littleEndian
)
contractAddress =
byteutils.toHex(metadataBytes[contractAddressOffset .. validRootsOffset - 1])
let validRootsBytes = metadataBytes[validRootsOffset .. metadataBytes.high]
validRoots = MerkleNodeSeq.deserialize(validRootsBytes)
return ok(
some(
RlnMetadata(
lastProcessedBlock: lastProcessedBlock,
chainId: chainId,
contractAddress: "0x" & contractAddress,
validRoots: validRoots,
)
)
)