2021-06-08 18:56:32 +00:00
2021-03-23 08:04:51 +00:00
{. used . }
2021-01-07 20:34:24 +00:00
import
2021-03-26 09:52:04 +00:00
std / options ,
testutils / unittests , chronos , chronicles , stint , web3 ,
2021-02-22 17:40:02 +00:00
stew / byteutils , stew / shims / net as stewNet ,
libp2p / crypto / crypto ,
2021-06-08 18:56:32 +00:00
.. / .. / waku / v2 / protocol / waku_rln_relay / [ rln , waku_rln_relay_utils , waku_rln_relay_types ] ,
2021-02-22 17:40:02 +00:00
.. / .. / waku / v2 / node / wakunode2 ,
2021-02-17 21:54:49 +00:00
.. / test_helpers ,
2021-03-26 09:52:04 +00:00
. / test_utils
2021-02-17 21:54:49 +00:00
2021-06-08 18:56:32 +00:00
2021-02-17 21:54:49 +00:00
# the address of Ethereum client (ganache-cli for now)
2021-02-22 17:40:02 +00:00
# TODO this address in hardcoded in the code, we may need to take it as input from the user
2021-02-17 21:54:49 +00:00
const EthClient = " ws://localhost:8540/ "
2021-02-19 19:44:18 +00:00
2021-02-04 20:10:25 +00:00
# poseidonHasherCode holds the bytecode of Poseidon hasher solidity smart contract:
# https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/crypto/PoseidonHasher.sol
# the solidity contract is compiled separately and the resultant bytecode is copied here
const poseidonHasherCode = readFile ( " tests/v2/poseidonHasher.txt " )
# membershipContractCode contains the bytecode of the membership solidity smart contract:
# https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/RLN.sol
# the solidity contract is compiled separately and the resultant bytecode is copied here
const membershipContractCode = readFile ( " tests/v2/membershipContract.txt " )
# the membership contract code in solidity
# uint256 public immutable MEMBERSHIP_DEPOSIT;
# uint256 public immutable DEPTH;
# uint256 public immutable SET_SIZE;
# uint256 public pubkeyIndex = 0;
# mapping(uint256 => uint256) public members;
# IPoseidonHasher public poseidonHasher;
# event MemberRegistered(uint256 indexed pubkey, uint256 indexed index);
# event MemberWithdrawn(uint256 indexed pubkey, uint256 indexed index);
# constructor(
# uint256 membershipDeposit,
# uint256 depth,
# address _poseidonHasher
# ) public {
# MEMBERSHIP_DEPOSIT = membershipDeposit;
# DEPTH = depth;
# SET_SIZE = 1 << depth;
# poseidonHasher = IPoseidonHasher(_poseidonHasher);
# }
# function register(uint256 pubkey) external payable {
# require(pubkeyIndex < SET_SIZE, "RLN, register: set is full");
# require(msg.value == MEMBERSHIP_DEPOSIT, "RLN, register: membership deposit is not satisfied");
# _register(pubkey);
# }
# function registerBatch(uint256[] calldata pubkeys) external payable {
# require(pubkeyIndex + pubkeys.length <= SET_SIZE, "RLN, registerBatch: set is full");
# require(msg.value == MEMBERSHIP_DEPOSIT * pubkeys.length, "RLN, registerBatch: membership deposit is not satisfied");
# for (uint256 i = 0; i < pubkeys.length; i++) {
# _register(pubkeys[i]);
# }
# }
# function withdrawBatch(
# uint256[] calldata secrets,
# uint256[] calldata pubkeyIndexes,
# address payable[] calldata receivers
# ) external {
# uint256 batchSize = secrets.length;
# require(batchSize != 0, "RLN, withdrawBatch: batch size zero");
# require(batchSize == pubkeyIndexes.length, "RLN, withdrawBatch: batch size mismatch pubkey indexes");
# require(batchSize == receivers.length, "RLN, withdrawBatch: batch size mismatch receivers");
# for (uint256 i = 0; i < batchSize; i++) {
# _withdraw(secrets[i], pubkeyIndexes[i], receivers[i]);
# }
# }
# function withdraw(
# uint256 secret,
# uint256 _pubkeyIndex,
# address payable receiver
# ) external {
# _withdraw(secret, _pubkeyIndex, receiver);
# }
2021-01-07 20:34:24 +00:00
contract ( MembershipContract ) :
2021-02-04 20:10:25 +00:00
proc register ( pubkey : Uint256 ) # external payable
# proc registerBatch(pubkeys: seq[Uint256]) # external payable
# TODO will add withdraw function after integrating the keyGeneration function (required to compute public keys from secret keys)
# proc withdraw(secret: Uint256, pubkeyIndex: Uint256, receiver: Address)
# proc withdrawBatch( secrets: seq[Uint256], pubkeyIndex: seq[Uint256], receiver: seq[Address])
2021-02-17 21:54:49 +00:00
proc uploadContract ( ethClientAddress : string ) : Future [ Address ] {. async . } =
let web3 = await newWeb3 ( ethClientAddress )
debug " web3 connected to " , ethClientAddress
2021-02-04 19:30:00 +00:00
# fetch the list of registered accounts
2021-01-07 20:34:24 +00:00
let accounts = await web3 . provider . eth_accounts ( )
web3 . defaultAccount = accounts [ 1 ]
2021-02-17 21:54:49 +00:00
let add = web3 . defaultAccount
debug " contract deployer account address " , add
2021-01-07 20:34:24 +00:00
var balance = await web3 . provider . eth_getBalance ( web3 . defaultAccount , " latest " )
2021-02-17 21:54:49 +00:00
debug " Initial account balance: " , balance
2021-01-07 20:34:24 +00:00
2021-02-04 20:10:25 +00:00
# deploy the poseidon hash first
let
hasherReceipt = await web3 . deployContract ( poseidonHasherCode )
hasherAddress = hasherReceipt . contractAddress . get
2021-02-17 21:54:49 +00:00
debug " hasher address: " , hasherAddress
2021-02-04 20:10:25 +00:00
2021-02-17 21:54:49 +00:00
2021-02-04 20:10:25 +00:00
# encode membership contract inputs to 32 bytes zero-padded
let
2021-02-17 21:54:49 +00:00
membershipFeeEncoded = encode ( MembershipFee ) . data
depthEncoded = encode ( Depth ) . data
2021-02-04 20:10:25 +00:00
hasherAddressEncoded = encode ( hasherAddress ) . data
# this is the contract constructor input
contractInput = membershipFeeEncoded & depthEncoded & hasherAddressEncoded
2021-02-17 21:54:49 +00:00
debug " encoded membership fee: " , membershipFeeEncoded
debug " encoded depth: " , depthEncoded
debug " encoded hasher address: " , hasherAddressEncoded
debug " encoded contract input: " , contractInput
2021-02-04 20:10:25 +00:00
# deploy membership contract with its constructor inputs
let receipt = await web3 . deployContract ( membershipContractCode , contractInput = contractInput )
2021-01-07 20:34:24 +00:00
var contractAddress = receipt . contractAddress . get
2021-02-17 21:54:49 +00:00
debug " Address of the deployed membership contract: " , contractAddress
2021-01-07 20:34:24 +00:00
2021-02-04 20:10:25 +00:00
# balance = await web3.provider.eth_getBalance(web3.defaultAccount , "latest")
2021-02-17 21:54:49 +00:00
# debug "Account balance after the contract deployment: ", balance
2021-01-07 20:34:24 +00:00
await web3 . close ( )
2021-02-17 21:54:49 +00:00
debug " disconnected from " , ethClientAddress
return contractAddress
procSuite " Waku rln relay " :
asyncTest " contract membership " :
let contractAddress = await uploadContract ( EthClient )
# connect to the eth client
let web3 = await newWeb3 ( EthClient )
debug " web3 connected to " , EthClient
# fetch the list of registered accounts
let accounts = await web3 . provider . eth_accounts ( )
web3 . defaultAccount = accounts [ 1 ]
let add = web3 . defaultAccount
debug " contract deployer account address " , add
# prepare a contract sender to interact with it
var sender = web3 . contractSender ( MembershipContract , contractAddress ) # creates a Sender object with a web3 field and contract address of type Address
# send takes three parameters, c: ContractCallBase, value = 0.u256, gas = 3000000'u64 gasPrice = 0
# should use send proc for the contract functions that update the state of the contract
let tx = await sender . register ( 20 . u256 ) . send ( value = MembershipFee )
debug " The hash of registration tx: " , tx # value is the membership fee
# var members: array[2, uint256] = [20.u256, 21.u256]
# debug "This is the batch registration result ", await sender.registerBatch(members).send(value = (members.len * membershipFee)) # value is the membership fee
# balance = await web3.provider.eth_getBalance(web3.defaultAccount , "latest")
# debug "Balance after registration: ", balance
await web3 . close ( )
debug " disconnected from " , EthClient
2021-02-19 19:44:18 +00:00
asyncTest " registration procedure " :
# deploy the contract
let contractAddress = await uploadContract ( EthClient )
# prepare rln-relay peer inputs
let
web3 = await newWeb3 ( EthClient )
accounts = await web3 . provider . eth_accounts ( )
# choose one of the existing accounts for the rln-relay peer
ethAccountAddress = accounts [ 9 ]
await web3 . close ( )
2021-03-24 17:26:56 +00:00
# create an RLN instance
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
2021-02-19 19:44:18 +00:00
# generate the membership keys
2021-04-01 00:39:27 +00:00
let membershipKeyPair = membershipKeyGen ( ctxPtr )
2021-02-19 19:44:18 +00:00
check :
membershipKeyPair . isSome
2021-02-22 17:40:02 +00:00
# initialize the WakuRLNRelay
var rlnPeer = WakuRLNRelay ( membershipKeyPair : membershipKeyPair . get ( ) ,
2021-02-19 19:44:18 +00:00
ethClientAddress : EthClient ,
ethAccountAddress : ethAccountAddress ,
membershipContractAddress : contractAddress )
# register the rln-relay peer to the membership contract
let is_successful = await rlnPeer . register ( )
check :
is_successful
2021-02-22 17:40:02 +00:00
asyncTest " mounting waku rln relay " :
let
nodeKey = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2021-07-14 17:58:46 +00:00
node = WakuNode . new ( nodeKey , ValidIpAddress . init ( " 0.0.0.0 " ) ,
2021-02-22 17:40:02 +00:00
Port ( 60000 ) )
await node . start ( )
# deploy the contract
let membershipContractAddress = await uploadContract ( EthClient )
# prepare rln-relay inputs
let
web3 = await newWeb3 ( EthClient )
accounts = await web3 . provider . eth_accounts ( )
# choose one of the existing account for the rln-relay peer
ethAccountAddress = accounts [ 9 ]
await web3 . close ( )
# start rln-relay
await node . mountRlnRelay ( ethClientAddress = some ( EthClient ) , ethAccountAddress = some ( ethAccountAddress ) , membershipContractAddress = some ( membershipContractAddress ) )
2021-03-22 09:44:45 +00:00
await node . stop ( )
2021-03-24 17:26:56 +00:00
2021-02-17 21:54:49 +00:00
suite " Waku rln relay " :
2021-03-24 17:26:56 +00:00
test " key_gen Nim Wrappers " :
2021-02-17 21:54:49 +00:00
var
merkleDepth : csize_t = 32
# parameters.key contains the parameters related to the Poseidon hasher
# to generate this file, clone this repo https://github.com/kilic/rln
# and run the following command in the root directory of the cloned project
# cargo run --example export_test_keys
# the file is generated separately and copied here
parameters = readFile ( " waku/v2/protocol/waku_rln_relay/parameters.key " )
pbytes = parameters . toBytes ( )
len : csize_t = uint ( pbytes . len )
2021-03-24 17:26:56 +00:00
parametersBuffer = Buffer ( ` ptr ` : addr ( pbytes [ 0 ] ) , len : len )
2021-02-17 21:54:49 +00:00
check :
# check the parameters.key is not empty
pbytes . len ! = 0
# ctx holds the information that is going to be used for the key generation
var
2021-03-24 17:26:56 +00:00
obj = RLN [ Bn256 ] ( )
objPtr = addr ( obj )
objptrptr = addr ( objPtr )
ctx = objptrptr
let res = new_circuit_from_params ( merkleDepth , addr parametersBuffer , ctx )
2021-02-17 21:54:49 +00:00
check :
# check whether the circuit parameters are generated successfully
res = = true
# keysBufferPtr will hold the generated key pairs i.e., secret and public keys
var
2021-03-24 17:26:56 +00:00
keysBuffer : Buffer
keysBufferPtr = addr ( keysBuffer )
done = key_gen ( ctx [ ] , keysBufferPtr )
2021-02-17 21:54:49 +00:00
check :
# check whether the keys are generated successfully
done = = true
if done :
var generatedKeys = cast [ ptr array [ 64 , byte ] ] ( keysBufferPtr . ` ptr ` ) [ ]
check :
# the public and secret keys together are 64 bytes
generatedKeys . len = = 64
2021-02-18 22:59:10 +00:00
debug " generated keys: " , generatedKeys
2021-06-08 18:56:32 +00:00
2021-02-18 22:59:10 +00:00
test " membership Key Gen " :
2021-03-24 17:26:56 +00:00
# create an RLN instance
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
2021-04-01 00:39:27 +00:00
var key = membershipKeyGen ( ctxPtr )
2021-02-18 22:59:10 +00:00
var empty : array [ 32 , byte ]
check :
key . isSome
key . get ( ) . secretKey . len = = 32
key . get ( ) . publicKey . len = = 32
key . get ( ) . secretKey ! = empty
key . get ( ) . publicKey ! = empty
2021-03-24 17:26:56 +00:00
debug " the generated membership key pair: " , key
2021-06-08 18:56:32 +00:00
2021-03-24 17:26:56 +00:00
test " get_root Nim binding " :
# create an RLN instance which also includes an empty Merkle tree
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
# read the Merkle Tree root
var
root1 {. noinit . } : Buffer = Buffer ( )
rootPtr1 = addr ( root1 )
2021-04-01 00:39:27 +00:00
get_root_successful1 = get_root ( ctxPtr , rootPtr1 )
2021-03-24 17:26:56 +00:00
doAssert ( get_root_successful1 )
doAssert ( root1 . len = = 32 )
# read the Merkle Tree root
var
root2 {. noinit . } : Buffer = Buffer ( )
rootPtr2 = addr ( root2 )
2021-04-01 00:39:27 +00:00
get_root_successful2 = get_root ( ctxPtr , rootPtr2 )
2021-03-24 17:26:56 +00:00
doAssert ( get_root_successful2 )
doAssert ( root2 . len = = 32 )
var rootValue1 = cast [ ptr array [ 32 , byte ] ] ( root1 . ` ptr ` )
let rootHex1 = rootValue1 [ ] . toHex
var rootValue2 = cast [ ptr array [ 32 , byte ] ] ( root2 . ` ptr ` )
let rootHex2 = rootValue2 [ ] . toHex
# the two roots must be identical
doAssert ( rootHex1 = = rootHex2 )
test " update_next_member Nim Wrapper " :
# create an RLN instance which also includes an empty Merkle tree
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
# generate a key pair
2021-04-01 00:39:27 +00:00
var keypair = membershipKeyGen ( ctxPtr )
2021-03-24 17:26:56 +00:00
doAssert ( keypair . isSome ( ) )
var pkBuffer = Buffer ( ` ptr ` : addr ( keypair . get ( ) . publicKey [ 0 ] ) , len : 32 )
let pkBufferPtr = addr pkBuffer
# add the member to the tree
2021-04-01 00:39:27 +00:00
var member_is_added = update_next_member ( ctxPtr , pkBufferPtr )
2021-03-24 17:26:56 +00:00
check :
member_is_added = = true
2021-06-08 18:56:32 +00:00
2021-03-24 17:26:56 +00:00
test " delete_member Nim wrapper " :
# create an RLN instance which also includes an empty Merkle tree
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
# delete the first member
var deleted_member_index = uint ( 0 )
2021-04-01 00:39:27 +00:00
let deletion_success = delete_member ( ctxPtr , deleted_member_index )
2021-03-24 17:26:56 +00:00
doAssert ( deletion_success )
2021-06-08 18:56:32 +00:00
2021-03-24 17:26:56 +00:00
test " Merkle tree consistency check between deletion and insertion " :
# create an RLN instance
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
2021-04-01 00:39:27 +00:00
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
2021-03-24 17:26:56 +00:00
# read the Merkle Tree root
var
root1 {. noinit . } : Buffer = Buffer ( )
rootPtr1 = addr ( root1 )
2021-04-01 00:39:27 +00:00
get_root_successful1 = get_root ( ctxPtr , rootPtr1 )
2021-03-24 17:26:56 +00:00
doAssert ( get_root_successful1 )
doAssert ( root1 . len = = 32 )
# generate a key pair
2021-04-01 00:39:27 +00:00
var keypair = membershipKeyGen ( ctxPtr )
2021-03-24 17:26:56 +00:00
doAssert ( keypair . isSome ( ) )
var pkBuffer = Buffer ( ` ptr ` : addr ( keypair . get ( ) . publicKey [ 0 ] ) , len : 32 )
let pkBufferPtr = addr pkBuffer
# add the member to the tree
2021-04-01 00:39:27 +00:00
var member_is_added = update_next_member ( ctxPtr , pkBufferPtr )
2021-03-24 17:26:56 +00:00
doAssert ( member_is_added )
# read the Merkle Tree root after insertion
var
root2 {. noinit . } : Buffer = Buffer ( )
rootPtr2 = addr ( root2 )
2021-04-01 00:39:27 +00:00
get_root_successful2 = get_root ( ctxPtr , rootPtr2 )
2021-03-24 17:26:56 +00:00
doAssert ( get_root_successful2 )
doAssert ( root2 . len = = 32 )
# delete the first member
var deleted_member_index = uint ( 0 )
2021-04-01 00:39:27 +00:00
let deletion_success = delete_member ( ctxPtr , deleted_member_index )
2021-03-24 17:26:56 +00:00
doAssert ( deletion_success )
# read the Merkle Tree root after the deletion
var
root3 {. noinit . } : Buffer = Buffer ( )
rootPtr3 = addr ( root3 )
2021-04-01 00:39:27 +00:00
get_root_successful3 = get_root ( ctxPtr , rootPtr3 )
2021-03-24 17:26:56 +00:00
doAssert ( get_root_successful3 )
doAssert ( root3 . len = = 32 )
var rootValue1 = cast [ ptr array [ 32 , byte ] ] ( root1 . ` ptr ` )
let rootHex1 = rootValue1 [ ] . toHex
debug " The initial root " , rootHex1
var rootValue2 = cast [ ptr array [ 32 , byte ] ] ( root2 . ` ptr ` )
let rootHex2 = rootValue2 [ ] . toHex
debug " The root after insertion " , rootHex2
var rootValue3 = cast [ ptr array [ 32 , byte ] ] ( root3 . ` ptr ` )
let rootHex3 = rootValue3 [ ] . toHex
debug " The root after deletion " , rootHex3
# the root must change after the insertion
doAssert ( not ( rootHex1 = = rootHex2 ) )
## The initial root of the tree (empty tree) must be identical to
## the root of the tree after one insertion followed by a deletion
2021-04-01 00:39:27 +00:00
doAssert ( rootHex1 = = rootHex3 )
test " hash Nim Wrappers " :
# create an RLN instance
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
doAssert ( createRLNInstance ( 30 , ctxPtr ) )
# prepare the input
var
hashInput : array [ 32 , byte ]
for x in hashInput . mitems : x = 1
var
hashInputHex = hashInput . toHex ( )
hashInputBuffer = Buffer ( ` ptr ` : addr hashInput [ 0 ] , len : 32 )
debug " sample_hash_input_bytes " , hashInputHex
# prepare other inputs to the hash function
var
outputBuffer : Buffer
numOfInputs = 1 . uint # the number of hash inputs that can be 1 or 2
let hashSuccess = hash ( ctxPtr , addr hashInputBuffer , numOfInputs , addr outputBuffer )
doAssert ( hashSuccess )
let outputArr = cast [ ptr array [ 32 , byte ] ] ( outputBuffer . ` ptr ` ) [ ]
doAssert ( " 53a6338cdbf02f0563cec1898e354d0d272c8f98b606c538945c6f41ef101828 " = = outputArr . toHex ( ) )
var
hashOutput = cast [ ptr array [ 32 , byte ] ] ( outputBuffer . ` ptr ` ) [ ]
hashOutputHex = hashOutput . toHex ( )
debug " hash output " , hashOutputHex
test " generate_proof and verify Nim Wrappers " :
# create an RLN instance
var
ctx = RLN [ Bn256 ] ( )
ctxPtr = addr ( ctx )
# check if the rln instance is created successfully
doAssert ( createRLNInstance ( 32 , ctxPtr ) )
# create the membership key
var auth = membershipKeyGen ( ctxPtr )
var skBuffer = Buffer ( ` ptr ` : addr ( auth . get ( ) . secretKey [ 0 ] ) , len : 32 )
# peer's index in the Merkle Tree
var index = 5
# prepare the authentication object with peer's index and sk
var authObj : Auth = Auth ( secret_buffer : addr skBuffer , index : uint ( index ) )
# Create a Merkle tree with random members
for i in 0 .. 10 :
var member_is_added : bool = false
if ( i = = index ) :
# insert the current peer's pk
var pkBuffer = Buffer ( ` ptr ` : addr ( auth . get ( ) . publicKey [ 0 ] ) , len : 32 )
member_is_added = update_next_member ( ctxPtr , addr pkBuffer )
else :
var memberKeys = membershipKeyGen ( ctxPtr )
var pkBuffer = Buffer ( ` ptr ` : addr ( memberKeys . get ( ) . publicKey [ 0 ] ) , len : 32 )
member_is_added = update_next_member ( ctxPtr , addr pkBuffer )
# check the member is added
doAssert ( member_is_added )
# prepare the message
var messageBytes {. noinit . } : array [ 32 , byte ]
for x in messageBytes . mitems : x = 1
var messageHex = messageBytes . toHex ( )
debug " message " , messageHex
# prepare the epoch
var epochBytes : array [ 32 , byte ]
for x in epochBytes . mitems : x = 0
var epochHex = epochBytes . toHex ( )
debug " epoch in bytes " , epochHex
# serialize message and epoch
# TODO add a proc for serializing
var epochMessage = @ epochBytes & @ messageBytes
doAssert ( epochMessage . len = = 64 )
var inputBytes {. noinit . } : array [ 64 , byte ] # holds epoch||Message
for ( i , x ) in inputBytes . mpairs : x = epochMessage [ i ]
var inputHex = inputBytes . toHex ( )
debug " serialized epoch and message " , inputHex
# put the serialized epoch||message into a buffer
var inputBuffer = Buffer ( ` ptr ` : addr ( inputBytes [ 0 ] ) , len : 64 )
# generate the proof
var proof : Buffer
let proofIsSuccessful = generate_proof ( ctxPtr , addr inputBuffer , addr authObj , addr proof )
# check whether the generate_proof call is done successfully
doAssert ( proofIsSuccessful )
var proofValue = cast [ ptr array [ 416 , byte ] ] ( proof . ` ptr ` )
let proofHex = proofValue [ ] . toHex
debug " proof content " , proofHex
# display the proof breakdown
var
zkSNARK = proofHex [ 0 .. 511 ]
proofRoot = proofHex [ 512 .. 575 ]
proofEpoch = proofHex [ 576 .. 639 ]
shareX = proofHex [ 640 .. 703 ]
shareY = proofHex [ 704 .. 767 ]
nullifier = proofHex [ 768 .. 831 ]
doAssert ( zkSNARK . len = = 512 )
doAssert ( proofRoot . len = = 64 )
doAssert ( proofEpoch . len = = 64 )
doAssert ( epochHex = = proofEpoch )
doAssert ( shareX . len = = 64 )
doAssert ( shareY . len = = 64 )
doAssert ( nullifier . len = = 64 )
debug " zkSNARK " , zkSNARK
debug " root " , proofRoot
debug " epoch " , proofEpoch
debug " shareX " , shareX
debug " shareY " , shareY
debug " nullifier " , nullifier
var f = 0 . uint32
let verifyIsSuccessful = verify ( ctxPtr , addr proof , addr f )
doAssert ( verifyIsSuccessful )
# f = 0 means the proof is verified
doAssert ( f = = 0 )
# create and test a bad proof
# prepare a bad authentication object with a wrong peer's index
var badIndex = 8
var badAuthObj : Auth = Auth ( secret_buffer : addr skBuffer , index : uint ( badIndex ) )
var badProof : Buffer
let badProofIsSuccessful = generate_proof ( ctxPtr , addr inputBuffer , addr badAuthObj , addr badProof )
# check whether the generate_proof call is done successfully
doAssert ( badProofIsSuccessful )
var badF = 0 . uint32
let badVerifyIsSuccessful = verify ( ctxPtr , addr badProof , addr badF )
doAssert ( badVerifyIsSuccessful )
# badF=1 means the proof is not verified
# verification of the bad proof should fail
doAssert ( badF = = 1 )