import * as assert from 'assert' ; import { PubKey , Command , Message , Keypair , StateLeaf , } from 'maci-domainobjs' ; import { hashLeftRight , stringifyBigInts , NOTHING_UP_MY_SLEEVE , IncrementalQuinTree , } from 'maci-crypto' ; import { User } from './User' ; class MaciState { public coordinatorKeypair : Keypair ; public users : User [ ] = [ ] ; public stateTreeDepth : number ; public messageTreeDepth : number ; public voteOptionTreeDepth : number ; public messages : Message [ ] = [ ] ; public zerothStateLeaf : StateLeaf ; public maxVoteOptionIndex : BigInt ; public encPubKeys : PubKey [ ] = [ ] ; private emptyVoteOptionTreeRoot ; private currentResultsSalt : BigInt = BigInt ( 0 ) ; public messageTree : IncrementalQuinTree ; constructor ( _coordinatorKeypair , _stateTreeDepth , _messageTreeDepth , _voteOptionTreeDepth , _maxVoteOptionIndex ) { this . coordinatorKeypair = _coordinatorKeypair ; this . stateTreeDepth = Number ( _stateTreeDepth ) ; this . messageTreeDepth = Number ( _messageTreeDepth ) ; this . voteOptionTreeDepth = Number ( _voteOptionTreeDepth ) ; this . maxVoteOptionIndex = BigInt ( _maxVoteOptionIndex ) ; const emptyVoteOptionTree = new IncrementalQuinTree ( this . voteOptionTreeDepth , BigInt ( 0 ) ) ; this . emptyVoteOptionTreeRoot = emptyVoteOptionTree . root ; this . zerothStateLeaf = this . genBlankLeaf ( ) ; this . messageTree = new IncrementalQuinTree ( this . messageTreeDepth , NOTHING_UP_MY_SLEEVE , 2 ) ; } private genBlankVotes = ( ) => { const votes = [ ] ; for ( let i = 0 ; i < 5 ** this . voteOptionTreeDepth ; i ++ ) { votes . push ( BigInt ( 0 ) ) ; } return votes ; } ; public genStateTree = ( ) : IncrementalQuinTree => { const stateTree = new IncrementalQuinTree ( this . stateTreeDepth , this . genBlankLeaf ( ) . hash ( ) , 2 ) ; stateTree . insert ( this . zerothStateLeaf . hash ( ) ) ; for ( const user of this . users ) { const stateLeaf = user . genStateLeaf ( this . voteOptionTreeDepth ) ; stateTree . insert ( stateLeaf . hash ( ) ) ; } return stateTree ; } ; public genStateRoot = ( ) : BigInt => { return this . genStateTree ( ) . root ; } ; public genMessageTree = ( ) : IncrementalQuinTree => { const messageTree = new IncrementalQuinTree ( this . messageTreeDepth , NOTHING_UP_MY_SLEEVE , 2 ) ; for ( const message of this . messages ) { messageTree . insert ( message . hash ( ) ) ; } return messageTree ; } ; public genMessageRoot = ( ) : BigInt => { return this . genMessageTree ( ) . root ; } ; public copy = ( ) : MaciState => { const copied = new MaciState ( this . coordinatorKeypair . copy ( ) , BigInt ( this . stateTreeDepth . toString ( ) ) , BigInt ( this . messageTreeDepth . toString ( ) ) , BigInt ( this . voteOptionTreeDepth . toString ( ) ) , BigInt ( this . maxVoteOptionIndex . toString ( ) ) ) ; copied . users = this . users . map ( ( x ) => x . copy ( ) ) ; copied . messages = this . messages . map ( ( x ) => x . copy ( ) ) ; copied . encPubKeys = this . encPubKeys . map ( ( x ) => x . copy ( ) ) ; copied . messageTree = this . messageTree . copy ( ) ; return copied ; } ; public signUp = ( _pubKey , _initialVoiceCreditBalance ) => { const user = new User ( _pubKey , this . genBlankVotes ( ) , _initialVoiceCreditBalance , BigInt ( 0 ) ) ; this . users . push ( user ) ; } ; public publishMessage = ( _message , _encPubKey ) => { this . encPubKeys . push ( _encPubKey ) ; this . messages . push ( _message ) ; this . messageTree . insert ( _message . hash ( ) ) ; } ; public processMessage = ( _index ) => { assert ( _index >= 0 ) ; assert ( this . messages . length > _index ) ; assert ( this . encPubKeys . length === this . messages . length ) ; const message = this . messages [ _index ] ; const encPubKey = this . encPubKeys [ _index ] ; const sharedKey = Keypair . genEcdhSharedKey ( this . coordinatorKeypair . privKey , encPubKey ) ; const { command , signature } = Command . decrypt ( message , sharedKey ) ; if ( command . stateIndex < BigInt ( 0 ) || command . newVoteWeight < BigInt ( 0 ) || command . nonce < BigInt ( 0 ) || command . salt < BigInt ( 0 ) || command . voteOptionIndex < BigInt ( 0 ) ) { return ; } if ( command . stateIndex > BigInt ( this . users . length ) ) { return ; } const userIndex = BigInt ( command . stateIndex ) - BigInt ( 1 ) ; assert ( BigInt ( this . users . length ) > userIndex ) ; const user = this . users [ Number ( userIndex ) ] ; if ( ! command . verifySignature ( signature , user . pubKey ) ) { return ; } if ( command . nonce !== BigInt ( user . nonce ) + BigInt ( 1 ) ) { return ; } const prevSpentCred = user . votes [ Number ( command . voteOptionIndex ) ] ; const voiceCreditsLeft = BigInt ( user . voiceCreditBalance ) + ( BigInt ( prevSpentCred ) * BigInt ( prevSpentCred ) ) - ( BigInt ( command . newVoteWeight ) * BigInt ( command . newVoteWeight ) ) ; if ( voiceCreditsLeft < 0 ) { return ; } if ( command . voteOptionIndex > this . maxVoteOptionIndex ) { return ; } const newUser = user . copy ( ) ; newUser . nonce = BigInt ( newUser . nonce ) + BigInt ( 1 ) ; newUser . votes [ Number ( command . voteOptionIndex ) ] = command . newVoteWeight ; newUser . voiceCreditBalance = voiceCreditsLeft ; newUser . pubKey = command . newPubKey . copy ( ) ; this . users [ Number ( userIndex ) ] = newUser ; } ; public batchProcessMessage = ( _index , _batchSize , _randomStateLeaf ) => { assert ( this . messages . length > _index ) ; for ( let i = 0 ; i < _batchSize ; i ++ ) { const messageIndex = _index + _batchSize - i - 1 ; if ( this . messages . length <= messageIndex ) { continue ; } this . processMessage ( messageIndex ) ; } this . zerothStateLeaf = _randomStateLeaf ; } ; public genUpdateStateTreeCircuitInputs = ( _index ) => { assert ( this . messages . length > _index ) ; assert ( this . encPubKeys . length === this . messages . length ) ; const message = this . messages [ _index ] ; const encPubKey = this . encPubKeys [ _index ] ; const sharedKey = Keypair . genEcdhSharedKey ( this . coordinatorKeypair . privKey , encPubKey ) ; const { command } = Command . decrypt ( message , sharedKey ) ; const msgTreePath = this . messageTree . genMerklePath ( _index ) ; assert ( IncrementalQuinTree . verifyMerklePath ( msgTreePath , this . messageTree . hashFunc ) ) ; const stateTree = this . genStateTree ( ) ; const stateTreeMaxIndex = BigInt ( stateTree . nextIndex ) - BigInt ( 1 ) ; const voteOptionTree = new IncrementalQuinTree ( this . voteOptionTreeDepth , BigInt ( 0 ) ) ; let userIndex ; let currentVoteWeight ; let stateTreePath ; let voteOptionTreePath ; let stateLeaf ; const stateIndex = Number ( command . stateIndex ) ; if ( Math . floor ( stateIndex ) === stateIndex && stateIndex >= 0 && Number ( command . stateIndex ) - 1 < this . users . length ) { userIndex = Number ( command . stateIndex ) - 1 ; const user = this . users [ userIndex ] ; currentVoteWeight = user . votes [ Number ( command . voteOptionIndex ) ] ; let lastZeroIndex = user . votes . length - 1 ; while ( BigInt ( user . votes [ lastZeroIndex ] ) === BigInt ( 0 ) && lastZeroIndex > 0 ) { lastZeroIndex -- ; } if ( lastZeroIndex < Number ( command . voteOptionIndex ) ) { lastZeroIndex = Number ( command . voteOptionIndex ) ; } for ( let i = 0 ; i <= lastZeroIndex ; i ++ ) { voteOptionTree . insert ( user . votes [ i ] ) ; } stateTreePath = stateTree . genMerklePath ( Number ( command . stateIndex ) ) ; voteOptionTreePath = voteOptionTree . genMerklePath ( Number ( command . voteOptionIndex ) ) ; stateLeaf = user . genStateLeaf ( this . voteOptionTreeDepth ) ; } else { currentVoteWeight = BigInt ( 0 ) ; stateLeaf = this . zerothStateLeaf ; stateTreePath = stateTree . genMerklePath ( 0 ) ; voteOptionTree . insert ( BigInt ( 0 ) ) ; voteOptionTreePath = voteOptionTree . genMerklePath ( 0 ) ; } return stringifyBigInts ( { 'coordinator_public_key' : this . coordinatorKeypair . pubKey . asCircuitInputs ( ) , 'ecdh_private_key' : this . coordinatorKeypair . privKey . asCircuitInputs ( ) , 'ecdh_public_key' : encPubKey . asCircuitInputs ( ) , 'message' : message . asCircuitInputs ( ) , 'msg_tree_root' : this . messageTree . root , 'msg_tree_path_elements' : msgTreePath . pathElements , 'msg_tree_path_index' : msgTreePath . indices , 'vote_options_leaf_raw' : currentVoteWeight , 'vote_options_tree_root' : voteOptionTree . root , 'vote_options_tree_path_elements' : voteOptionTreePath . pathElements , 'vote_options_tree_path_index' : voteOptionTreePath . indices , 'vote_options_max_leaf_index' : this . maxVoteOptionIndex , 'state_tree_data_raw' : stateLeaf . asCircuitInputs ( ) , 'state_tree_max_leaf_index' : stateTreeMaxIndex , 'state_tree_root' : stateTree . root , 'state_tree_path_elements' : stateTreePath . pathElements , 'state_tree_path_index' : stateTreePath . indices } ) ; } ; public genBatchUpdateStateTreeCircuitInputs = ( _index , _batchSize , _randomStateLeaf ) => { assert ( this . messages . length > _index ) ; assert ( this . encPubKeys . length === this . messages . length ) ; const stateLeaves = [ ] ; const stateRoots = [ ] ; const stateTreePathElements = [ ] ; const stateTreePathIndices = [ ] ; const voteOptionLeaves = [ ] ; const voteOptionTreeRoots = [ ] ; const voteOptionTreePathElements = [ ] ; const voteOptionTreePathIndices = [ ] ; const messageTreePathElements = [ ] ; const messages = [ ] ; const encPubKeys = [ ] ; const clonedMaciState = this . copy ( ) ; const messageTree = clonedMaciState . messageTree ; let numRealMessages = BigInt ( 0 ) ; const messageIndices = [ ] ; for ( let i = 0 ; i < _batchSize ; i ++ ) { const j = _index + i ; if ( j < BigInt ( clonedMaciState . messages . length ) ) { messageIndices . push ( _index + i ) ; numRealMessages = numRealMessages + BigInt ( 1 ) ; } else { messageIndices . push ( clonedMaciState . messages . length - 1 ) ; } } messageIndices . reverse ( ) ; let messageIndex ; for ( let i = 0 ; i < _batchSize ; i ++ ) { messageIndex = messageIndices [ i ] ; const ustCircuitInputs = clonedMaciState . genUpdateStateTreeCircuitInputs ( messageIndex ) ; if ( messageIndex < BigInt ( clonedMaciState . messages . length ) ) { clonedMaciState . processMessage ( messageIndex ) ; } messages . push ( clonedMaciState . messages [ messageIndex ] ) ; encPubKeys . push ( clonedMaciState . encPubKeys [ messageIndex ] ) ; messageTreePathElements . push ( ustCircuitInputs . msg_tree_path_elements ) ; stateRoots . push ( ustCircuitInputs . state_tree_root ) ; stateTreePathElements . push ( ustCircuitInputs . state_tree_path_elements ) ; stateTreePathIndices . push ( ustCircuitInputs . state_tree_path_index ) ; voteOptionLeaves . push ( ustCircuitInputs . vote_options_leaf_raw ) ; stateLeaves . push ( ustCircuitInputs . state_tree_data_raw ) ; voteOptionTreeRoots . push ( ustCircuitInputs . vote_options_tree_root ) ; voteOptionTreePathElements . push ( ustCircuitInputs . vote_options_tree_path_elements ) ; voteOptionTreePathIndices . push ( ustCircuitInputs . vote_options_tree_path_index ) ; } const stateTree = clonedMaciState . genStateTree ( ) ; const randomLeafRoot = stateTree . root ; stateTree . update ( 0 , _randomStateLeaf . hash ( ) ) ; const randomStateLeafPathElements = stateTree . genMerklePath ( 0 ) . pathElements ; return stringifyBigInts ( { 'coordinator_public_key' : clonedMaciState . coordinatorKeypair . pubKey . asCircuitInputs ( ) , 'message' : messages . map ( ( x ) => x . asCircuitInputs ( ) ) , 'ecdh_private_key' : clonedMaciState . coordinatorKeypair . privKey . asCircuitInputs ( ) , 'ecdh_public_key' : encPubKeys . map ( ( x ) => x . asCircuitInputs ( ) ) , 'msg_tree_root' : messageTree . root , 'msg_tree_path_elements' : messageTreePathElements , 'msg_tree_batch_start_index' : _index , 'msg_tree_batch_end_index' : BigInt ( _index ) + numRealMessages - BigInt ( 1 ) , 'random_leaf' : _randomStateLeaf . hash ( ) , 'state_tree_root' : stateRoots , 'state_tree_path_elements' : stateTreePathElements , 'state_tree_path_index' : stateTreePathIndices , 'random_leaf_root' : randomLeafRoot , 'random_leaf_path_elements' : randomStateLeafPathElements , 'vote_options_leaf_raw' : voteOptionLeaves , 'state_tree_data_raw' : stateLeaves , 'state_tree_max_leaf_index' : BigInt ( stateTree . nextIndex ) - BigInt ( 1 ) , 'vote_options_max_leaf_index' : clonedMaciState . maxVoteOptionIndex , 'vote_options_tree_root' : voteOptionTreeRoots , 'vote_options_tree_path_elements' : voteOptionTreePathElements , 'vote_options_tree_path_index' : voteOptionTreePathIndices } ) ; } ; public computeCumulativePerVOSpentVoiceCredits = ( _startIndex ) : BigInt [ ] => { _startIndex = BigInt ( _startIndex ) ; assert ( BigInt ( this . users . length ) >= _startIndex ) ; const results = [ ] ; for ( let i = 0 ; i < 5 ** this . voteOptionTreeDepth ; i ++ ) { results . push ( BigInt ( 0 ) ) ; } for ( let i = 0 ; i < Number ( _startIndex ) - 1 ; i ++ ) { const user = this . users [ i ] ; for ( let j = 0 ; j < user . votes . length ; j ++ ) { results [ j ] = BigInt ( results [ j ] ) + BigInt ( user . votes [ j ] ) * BigInt ( user . votes [ j ] ) ; } } return results ; } ; public computeCumulativeSpentVoiceCredits = ( _startIndex ) : BigInt => { _startIndex = BigInt ( _startIndex ) ; assert ( BigInt ( this . users . length ) >= _startIndex ) ; if ( _startIndex === BigInt ( 0 ) ) { return BigInt ( 0 ) ; } let result = BigInt ( 0 ) ; for ( let i = 0 ; i < Number ( _startIndex ) - 1 ; i ++ ) { const user = this . users [ i ] ; for ( let j = 0 ; j < user . votes . length ; j ++ ) { result = BigInt ( result ) + BigInt ( user . votes [ j ] ) * BigInt ( user . votes [ j ] ) ; } } return result ; } ; public computeBatchSpentVoiceCredits = ( _startIndex , _batchSize ) : BigInt => { _startIndex = BigInt ( _startIndex ) ; assert ( _startIndex >= BigInt ( 0 ) && _startIndex <= BigInt ( this . users . length ) ) ; assert ( BigInt ( _startIndex ) % BigInt ( _batchSize ) === BigInt ( 0 ) ) ; if ( _startIndex === BigInt ( 0 ) ) { _batchSize -- ; } else { _startIndex = BigInt ( _startIndex ) - BigInt ( 1 ) ; } let result = BigInt ( 0 ) ; for ( let i = 0 ; i < _batchSize ; i ++ ) { const userIndex = BigInt ( _startIndex ) + BigInt ( i ) ; if ( userIndex < this . users . length ) { for ( const vote of this . users [ Number ( userIndex ) ] . votes ) { result += BigInt ( vote ) * BigInt ( vote ) ; } } else { break ; } } return result ; } ; public computeBatchPerVOSpentVoiceCredits = ( _startIndex , _batchSize ) : BigInt [ ] => { _startIndex = BigInt ( _startIndex ) ; assert ( _startIndex >= BigInt ( 0 ) && _startIndex <= BigInt ( this . users . length ) ) ; assert ( BigInt ( _startIndex ) % BigInt ( _batchSize ) === BigInt ( 0 ) ) ; if ( _startIndex === BigInt ( 0 ) ) { _batchSize -- ; } else { _startIndex = BigInt ( _startIndex ) - BigInt ( 1 ) ; } const results = [ ] ; for ( let i = 0 ; i < 5 ** this . voteOptionTreeDepth ; i ++ ) { results . push ( BigInt ( 0 ) ) ; } for ( let i = 0 ; i < _batchSize ; i ++ ) { const userIndex = BigInt ( _startIndex ) + BigInt ( i ) ; if ( userIndex < this . users . length ) { const votes = this . users [ Number ( userIndex ) ] . votes ; for ( let j = 0 ; j < votes . length ; j ++ ) { results [ j ] = BigInt ( results [ j ] ) + BigInt ( votes [ j ] ) * BigInt ( votes [ j ] ) ; } } else { break ; } } return results ; } ; public computeCumulativeVoteTally = ( _startIndex ) : BigInt [ ] => { assert ( BigInt ( this . users . length ) >= _startIndex ) ; const results = [ ] ; for ( let i = 0 ; i < 5 ** this . voteOptionTreeDepth ; i ++ ) { results . push ( BigInt ( 0 ) ) ; } for ( let i = 0 ; i < Number ( _startIndex ) - 1 ; i ++ ) { const user = this . users [ i ] ; for ( let j = 0 ; j < user . votes . length ; j ++ ) { results [ j ] = BigInt ( results [ j ] ) + BigInt ( user . votes [ j ] ) ; } } return results ; } ; public computeBatchVoteTally = ( _startIndex , _batchSize ) : BigInt [ ] => { _startIndex = BigInt ( _startIndex ) ; assert ( _startIndex >= BigInt ( 0 ) && _startIndex <= BigInt ( this . users . length ) ) ; assert ( BigInt ( _startIndex ) % BigInt ( _batchSize ) === BigInt ( 0 ) ) ; const results = [ ] ; for ( let i = 0 ; i < 5 ** this . voteOptionTreeDepth ; i ++ ) { results . push ( BigInt ( 0 ) ) ; } if ( _startIndex === BigInt ( 0 ) ) { _batchSize -- ; } else { _startIndex = BigInt ( _startIndex ) - BigInt ( 1 ) ; } for ( let i = 0 ; i < _batchSize ; i ++ ) { const userIndex = BigInt ( _startIndex ) + BigInt ( i ) ; if ( userIndex < this . users . length ) { const votes = this . users [ Number ( userIndex ) ] . votes ; for ( let j = 0 ; j < votes . length ; j ++ ) { results [ j ] = BigInt ( results [ j ] ) + BigInt ( votes [ j ] ) ; } } else { break ; } } return results ; } ; public genBlankLeaf = ( ) : StateLeaf => { return StateLeaf . genBlankLeaf ( this . emptyVoteOptionTreeRoot ) ; } ; public genQuadVoteTallyCircuitInputs = ( _startIndex , _batchSize , _currentResultsSalt , _newResultsSalt , _currentSpentVoiceCreditsSalt , _newSpentVoiceCreditsSalt , _currentPerVOSpentVoiceCreditsSalt , _newPerVOSpentVoiceCreditsSalt ) => { _startIndex = BigInt ( _startIndex ) ; _currentResultsSalt = BigInt ( _currentResultsSalt ) ; _newResultsSalt = BigInt ( _newResultsSalt ) ; if ( _startIndex === BigInt ( 0 ) ) { assert ( _currentResultsSalt === BigInt ( 0 ) ) ; } const currentPerVOSpentVoiceCredits = this . computeCumulativePerVOSpentVoiceCredits ( _startIndex ) ; const currentPerVOSpentVoiceCreditsCommitment = genPerVOSpentVoiceCreditsCommitment ( currentPerVOSpentVoiceCredits , _currentPerVOSpentVoiceCreditsSalt , this . voteOptionTreeDepth ) ; const currentSpentVoiceCredits = this . computeCumulativeSpentVoiceCredits ( _startIndex ) ; const currentSpentVoiceCreditsCommitment = genSpentVoiceCreditsCommitment ( currentSpentVoiceCredits , _currentSpentVoiceCreditsSalt ) ; const currentResults = this . computeCumulativeVoteTally ( _startIndex ) ; const batchResults = this . computeBatchVoteTally ( _startIndex , _batchSize ) ; assert ( currentResults . length === batchResults . length ) ; const newResults = [ ] ; for ( let i = 0 ; i < currentResults . length ; i ++ ) { newResults [ i ] = BigInt ( currentResults [ i ] ) + BigInt ( batchResults [ i ] ) ; } const currentResultsCommitment = genTallyResultCommitment ( currentResults , _currentResultsSalt , this . voteOptionTreeDepth ) ; const blankStateLeaf = this . genBlankLeaf ( ) ; const blankStateLeafHash = blankStateLeaf . hash ( ) ; const batchTreeDepth = Math . log2 ( Number ( _batchSize ) ) ; const stateLeaves = [ ] ; const voteLeaves = [ ] ; if ( _startIndex === BigInt ( 0 ) ) { stateLeaves . push ( this . zerothStateLeaf ) ; voteLeaves . push ( this . genBlankVotes ( ) ) ; } for ( let i = 0 ; i < _batchSize ; i ++ ) { if ( _startIndex === BigInt ( 0 ) && i === 0 ) { continue ; } const userIndex = Number ( _startIndex ) + i - 1 ; if ( userIndex < this . users . length ) { stateLeaves . push ( this . users [ userIndex ] . genStateLeaf ( this . voteOptionTreeDepth ) ) ; voteLeaves . push ( this . users [ userIndex ] . votes ) ; } else { stateLeaves . push ( blankStateLeaf ) ; voteLeaves . push ( this . genBlankVotes ( ) ) ; } } const emptyBatchTree = new IncrementalQuinTree ( batchTreeDepth , blankStateLeafHash , 2 ) ; const intermediateTree = new IncrementalQuinTree ( this . stateTreeDepth - batchTreeDepth , emptyBatchTree . root , 2 ) ; const numBatches = ( this . users . length + 1 ) % Number ( _batchSize ) === 0 ? ( this . users . length + 1 ) / Number ( _batchSize ) : Math . floor ( ( this . users . length + 1 ) / Number ( _batchSize ) ) + 1 ; for ( let i = 0 ; i < numBatches * Number ( _batchSize ) ; i += Number ( _batchSize ) ) { const batchTree = emptyBatchTree . copy ( ) ; for ( let j = 0 ; j < Number ( _batchSize ) ; j ++ ) { if ( i === 0 && j === 0 ) { batchTree . insert ( this . zerothStateLeaf . hash ( ) ) ; } else { const userIndex = i + j - 1 ; if ( userIndex < this . users . length ) { const leaf = this . users [ userIndex ] . genStateLeaf ( Number ( this . voteOptionTreeDepth ) ) . hash ( ) ; batchTree . insert ( leaf ) ; } } } intermediateTree . insert ( batchTree . root ) ; } assert ( intermediateTree . root === this . genStateRoot ( ) ) ; const intermediatePathIndex = BigInt ( _startIndex ) / BigInt ( _batchSize ) ; const intermediateStateRoot = intermediateTree . leaves [ Number ( intermediatePathIndex ) ] ; const intermediatePathElements = intermediateTree . genMerklePath ( Number ( intermediatePathIndex ) ) . pathElements ; const a = BigInt ( Math . ceil ( ( this . users . length + 1 ) / Number ( _batchSize ) ) - 1 ) ; const isLastBatch = intermediatePathIndex === a ; const circuitInputs = stringifyBigInts ( { isLastBatch : isLastBatch ? BigInt ( 1 ) : BigInt ( 0 ) , voteLeaves , stateLeaves : stateLeaves . map ( ( x ) => x . asCircuitInputs ( ) ) , fullStateRoot : this . genStateRoot ( ) , currentResults , currentResultsCommitment , currentResultsSalt : _currentResultsSalt , newResultsSalt : _newResultsSalt , currentSpentVoiceCredits , currentSpentVoiceCreditsSalt : _currentSpentVoiceCreditsSalt , currentSpentVoiceCreditsCommitment , newSpentVoiceCreditsSalt : _newSpentVoiceCreditsSalt , currentPerVOSpentVoiceCredits , currentPerVOSpentVoiceCreditsCommitment , currentPerVOSpentVoiceCreditsSalt : _currentPerVOSpentVoiceCreditsSalt , newPerVOSpentVoiceCreditsSalt : _newPerVOSpentVoiceCreditsSalt , intermediatePathElements , intermediatePathIndex , intermediateStateRoot } ) ; return circuitInputs ; } ; } const genSpentVoiceCreditsCommitment = ( vc , salt ) : BigInt => { return hashLeftRight ( vc , salt ) ; } ; const genTallyResultCommitment = ( results , salt , voteOptionTreeDepth ) : BigInt => { const tree = new IncrementalQuinTree ( voteOptionTreeDepth , BigInt ( 0 ) ) ; for ( const result of results ) { tree . insert ( BigInt ( result ) ) ; } return hashLeftRight ( tree . root , salt ) ; } ; const genPerVOSpentVoiceCreditsCommitment = genTallyResultCommitment ; export { genPerVOSpentVoiceCreditsCommitment , genSpentVoiceCreditsCommitment , genTallyResultCommitment , MaciState , } ;