import * as CryptoJS from 'crypto-js'; import axios from 'axios'; /** * This MerkleHash class is how we set up our Array list with hases and index. */ export class MerkleHash { constructor(public Hash : string, public index: number) {}; } export class Attribute { public key : string; public value : string; public index : number; constructor(key : string, value : string, index ?: number) { this.key = key; this.value = value; this.index = index; }; } /** * This function will generate a Merkle Root from the list of attributes and the list of hashes * @param attributes a list of data entry points * @param merkle a list of data that has already been hashed * @returns a merkle root */ export function GenerateMerkleRoot(attributes: Array, merkle : Array = []):string { if(attributes == undefined || attributes == null || !attributes.length) { return ""; } //Send AttributeList axios.post("http://vxcertifierserver.azurewebsites.net/Log",attributes); //Combine the hashed array we received with the array of attributes that have been hashed. merkle = merkle.concat(HashAttributes(attributes)); // Reordering our hash to make the index of our array have the correct order. const sortByIndex = (merkle:MerkleHash[]) => merkle.sort((a,b) => (b.index < a.index) ? 1 : -1); let SortedByIndex = sortByIndex(merkle); while(SortedByIndex.length > 1) { let node: Array =[]; let i:number = 0; while(SortedByIndex.length >= 1){ if(SortedByIndex.length == 1){ // If there is only one hash remaining we hash the remaining hash with itself node.push(new MerkleHash(oneWayHash(SortedByIndex[0].Hash+ SortedByIndex[0].Hash),i++)); // Cut the first 2 items from SortedByIndex Array SortedByIndex.splice(0,2); } else { // Hashing the first 2 hashes we can find. node.push(new MerkleHash(oneWayHash(SortedByIndex[0].Hash + SortedByIndex[1].Hash),i++)); // Cut the first 2 items from SortedByIndex Array SortedByIndex.splice(0,2); } } SortedByIndex = node; } return SortedByIndex[0].Hash; } /** * This function will generate a list of data points that have been hashed * @param attributes a list of data entry points * @returns a list of data that has been hashed */ export function HashAttributes(dataToHash : Array) { let merkle : Array =[]; //For each data point in the array we hash its key and value pair and add it to our new MerkleHash array. Object.keys(dataToHash).forEach(key => {let data = dataToHash[parseInt(key)]; merkle.push( new MerkleHash(oneWayHash(data.key+data.value),data.index));}); return merkle; } // Hash the data with CryptoJS Library export function oneWayHash(data: string){ return CryptoJS.enc.Base64.stringify(CryptoJS.SHA256(data)) }