2023-01-16 12:56:18 +00:00
when ( NimMajor , NimMinor ) < ( 1 , 4 ) :
{. push raises : [ Defect ] . }
else :
{. push raises : [ ] . }
import
std / [ sequtils ] ,
web3 ,
chronicles ,
stew / [ arrayops , results , endians2 ] ,
stint
import
2023-02-08 15:26:23 +00:00
. / constants ,
2023-01-16 12:56:18 +00:00
. / protocol_types
import
2023-02-08 15:26:23 +00:00
.. / waku_keystore
2023-01-16 12:56:18 +00:00
export
web3 ,
chronicles ,
stint
logScope :
topics = " waku rln_relay conversion_utils "
proc toUInt256 * ( idCommitment : IDCommitment ) : UInt256 =
let pk = UInt256 . fromBytesLE ( idCommitment )
return pk
proc toIDCommitment * ( idCommitmentUint : UInt256 ) : IDCommitment =
2023-02-08 15:26:23 +00:00
let pk = IDCommitment ( @ ( idCommitmentUint . toBytesLE ( ) ) )
2023-01-16 12:56:18 +00:00
return pk
proc toMembershipIndex * ( v : UInt256 ) : MembershipIndex =
let membershipIndex : MembershipIndex = cast [ MembershipIndex ] ( v )
return membershipIndex
proc appendLength * ( input : openArray [ byte ] ) : seq [ byte ] =
## returns length prefixed version of the input
## with the following format [len<8>|input<var>]
## len: 8-byte value that represents the number of bytes in the `input`
## len is serialized in little-endian
## input: the supplied `input`
let
# the length should be serialized in little-endian
len = toBytes ( uint64 ( input . len ) , Endianness . littleEndian )
output = concat ( @ len , @ input )
return output
proc serialize * ( idSecretHash : IdentitySecretHash , memIndex : MembershipIndex , epoch : Epoch ,
msg : openArray [ byte ] ) : seq [ byte ] =
## a private proc to convert RateLimitProof and the data to a byte seq
## this conversion is used in the proofGen proc
## the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146
## [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
let memIndexBytes = toBytes ( uint64 ( memIndex ) , Endianness . littleEndian )
let lenPrefMsg = appendLength ( msg )
let output = concat ( @ idSecretHash , @ memIndexBytes , @ epoch , lenPrefMsg )
return output
proc serialize * ( proof : RateLimitProof , data : openArray [ byte ] ) : seq [ byte ] =
## a private proc to convert RateLimitProof and data to a byte seq
## this conversion is used in the proof verification proc
## [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
let lenPrefMsg = appendLength ( @ data )
var proofBytes = concat ( @ ( proof . proof ) ,
@ ( proof . merkleRoot ) ,
@ ( proof . epoch ) ,
@ ( proof . shareX ) ,
@ ( proof . shareY ) ,
@ ( proof . nullifier ) ,
@ ( proof . rlnIdentifier ) ,
lenPrefMsg )
return proofBytes
# Serializes a sequence of MerkleNodes
proc serialize * ( roots : seq [ MerkleNode ] ) : seq [ byte ] =
var rootsBytes : seq [ byte ] = @ [ ]
for root in roots :
rootsBytes = concat ( rootsBytes , @ root )
return rootsBytes
proc serializeIdCommitments * ( idComms : seq [ IDCommitment ] ) : seq [ byte ] =
## serializes a seq of IDCommitments to a byte seq
## the serialization is based on https://github.com/status-im/nwaku/blob/37bd29fbc37ce5cf636734e7dd410b1ed27b88c8/waku/v2/protocol/waku_rln_relay/rln.nim#L142
## the order of serialization is |id_commitment_len<8>|id_commitment<var>|
var idCommsBytes = newSeq [ byte ] ( )
# serialize the idComms, with its length prefixed
let len = toBytes ( uint64 ( idComms . len ) , Endianness . littleEndian )
idCommsBytes . add ( len )
for idComm in idComms :
idCommsBytes = concat ( idCommsBytes , @ idComm )
return idCommsBytes
# Converts a sequence of tuples containing 4 string (i.e. identity trapdoor, nullifier, secret hash and commitment) to an IndentityCredential
proc toIdentityCredentials * ( groupKeys : seq [ ( string , string , string , string ) ] ) : RlnRelayResult [ seq [
IdentityCredential ] ] =
## groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format
## the toIdentityCredentials proc populates a sequence of IdentityCredentials using the supplied groupKeys
## Returns an error if the conversion fails
var groupIdCredentials = newSeq [ IdentityCredential ] ( )
for i in 0 .. groupKeys . len - 1 :
try :
let
2023-02-08 15:26:23 +00:00
idTrapdoor = IdentityTrapdoor ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 0 ] ) . toBytesLE ( ) ) )
idNullifier = IdentityNullifier ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 1 ] ) . toBytesLE ( ) ) )
idSecretHash = IdentitySecretHash ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 2 ] ) . toBytesLE ( ) ) )
idCommitment = IDCommitment ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 3 ] ) . toBytesLE ( ) ) )
2023-01-16 12:56:18 +00:00
groupIdCredentials . add ( IdentityCredential ( idTrapdoor : idTrapdoor , idNullifier : idNullifier , idSecretHash : idSecretHash ,
idCommitment : idCommitment ) )
except ValueError as err :
warn " could not convert the group key to bytes " , err = err . msg
return err ( " could not convert the group key to bytes: " & err . msg )
return ok ( groupIdCredentials )
# Converts a sequence of tuples containing 2 string (i.e. identity secret hash and commitment) to an IndentityCredential
proc toIdentityCredentials * ( groupKeys : seq [ ( string , string ) ] ) : RlnRelayResult [ seq [
IdentityCredential ] ] =
## groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format
## the toIdentityCredentials proc populates a sequence of IdentityCredentials using the supplied groupKeys
## Returns an error if the conversion fails
var groupIdCredentials = newSeq [ IdentityCredential ] ( )
for i in 0 .. groupKeys . len - 1 :
try :
let
2023-02-08 15:26:23 +00:00
idSecretHash = IdentitySecretHash ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 0 ] ) . toBytesLE ( ) ) )
idCommitment = IDCommitment ( @ ( hexToUint [ CredentialByteSize ] ( groupKeys [ i ] [ 1 ] ) . toBytesLE ( ) ) )
2023-01-16 12:56:18 +00:00
groupIdCredentials . add ( IdentityCredential ( idSecretHash : idSecretHash ,
idCommitment : idCommitment ) )
except ValueError as err :
warn " could not convert the group key to bytes " , err = err . msg
return err ( " could not convert the group key to bytes: " & err . msg )
return ok ( groupIdCredentials )
proc toEpoch * ( t : uint64 ) : Epoch =
## converts `t` to `Epoch` in little-endian order
let bytes = toBytes ( t , Endianness . littleEndian )
debug " bytes " , bytes = bytes
var epoch : Epoch
discard epoch . copyFrom ( bytes )
return epoch
proc fromEpoch * ( epoch : Epoch ) : uint64 =
## decodes bytes of `epoch` (in little-endian) to uint64
let t = fromBytesLE ( uint64 , array [ 32 , byte ] ( epoch ) )
return t