import * as cryptoJS from 'crypto-js' ; import { ClaimProof } from './claim/claimProof' ; import RestClient from './network/rest/restClient' ; export function verifyLeafHashInclusion ( leafHash , leafIndex , proof , rootHash , treeSize ) { if ( treeSize <= leafIndex ) { throw new Error ( 'Wrong params, the tree size is smaller than the leaf index' ) ; } const calculatedRootHash = calculateRootHashFromAuditPath ( leafHash , leafIndex , proof , treeSize ) ; if ( calculatedRootHash !== rootHash ) { return false ; } return true ; } export function calculateRootHashFromAuditPath ( leafHash , leafIndex , proof , treeSize ) { let calculatedHash = leafHash ; let lastNode = treeSize - 1 ; let pos = 0 ; const pathLen = proof . length ; while ( lastNode > 0 ) { if ( pos > pathLen ) { throw new Error ( 'Proof too short' ) ; } if ( leafIndex % 2 === 1 ) { calculatedHash = hashChildren ( proof [ pos ] , calculatedHash ) ; pos += 1 ; } else if ( leafIndex < lastNode ) { calculatedHash = hashChildren ( calculatedHash , proof [ pos ] ) ; pos += 1 ; } leafIndex = Math . floor ( leafIndex / 2 ) ; lastNode = Math . floor ( lastNode / 2 ) ; } if ( pos < pathLen ) { throw new Error ( 'Proof too long' ) ; } return calculatedHash ; } export function hashChildren ( left , right ) { let data = '01' + left ; data += right ; const hex = cryptoJS . enc . Hex . parse ( data ) ; return cryptoJS . SHA256 ( hex ) . toString ( ) ; } export function getProofNodes ( leafIndex , treeSize , proof ) { let lastNode = treeSize - 1 ; let pos = 0 ; const pathLen = proof . length ; const nodes = [ ] ; while ( lastNode > 0 ) { if ( pos > pathLen ) { throw new Error ( 'Proof too short' ) ; } const node = { TargetHash : proof [ pos ] , Direction : '' } ; if ( leafIndex % 2 === 1 ) { node . Direction = 'Left' ; pos += 1 ; } else if ( leafIndex < lastNode ) { node . Direction = 'Right' ; pos += 1 ; } nodes . push ( node ) ; leafIndex = Math . floor ( leafIndex / 2 ) ; lastNode = Math . floor ( lastNode / 2 ) ; } return nodes ; } export async function constructMerkleProof ( restUrl , txHash , contractAddr ) { const restClient = new RestClient ( restUrl ) ; const res = await restClient . getMerkleProof ( txHash ) ; const merkleProof = res . Result ; const proof = merkleProof . TargetHashes ; const leafIndex = merkleProof . BlockHeight ; const treeSize = merkleProof . CurBlockHeight ; const nodes = getProofNodes ( leafIndex , treeSize , proof ) ; const claimProof = { Type : 'MerkleProof' , TxnHash : txHash , ContractAddr : contractAddr , BlockHeight : merkleProof . BlockHeight , MerkleRoot : merkleProof . CurBlockRoot , Nodes : nodes } as ClaimProof ; return claimProof ; } export function verifyClaimProof ( txHash , merkleRoot , nodes ) { let p = txHash ; for ( const n of nodes ) { if ( n . Direction === 'Right' ) { p = hashChildren ( p , n . TargetHash ) ; } else if ( n . Direction === 'Left' ) { p = hashChildren ( n . TargetHash , p ) ; } } if ( p === merkleRoot ) { return true ; } else { return false ; } }