amazon-qldb-kvs-nodejs
Version:
A helper module, simplifying basic interactions with Amazon Quantum Ledger Database for Node.js through a simple key-value store interface.
91 lines (90 loc) • 3.31 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRevisionHash = void 0;
const ion_hash_js_1 = require("ion-hash-js");
const ion_js_1 = require("ion-js");
const crypto_1 = require("crypto");
const Logging_1 = require("./Logging");
const Util_1 = require("./Util");
const logger = Logging_1.log.getLogger("qldb-helper");
const HASH_LENGTH = 32;
/**
* Take two hash values, sort them, concatenate them, and generate a new hash value from the concatenated values.
* @param h1 Byte array containing one of the hashes to compare.
* @param h2 Byte array containing one of the hashes to compare.
* @returns The concatenated array of hashes.
*/
function joinHashesPairwise(h1, h2) {
if (h1.length === 0) {
return Buffer.from(h2);
}
if (h2.length === 0) {
return Buffer.from(h1);
}
let concat;
if (compareHashValues(h1, h2) < 0) {
concat = concatenate(h1, h2);
}
else {
concat = concatenate(h2, h1);
}
const hash = (0, crypto_1.createHash)('sha256');
hash.update(concat);
// Return new digest
return hash.digest();
}
/**
* Compare two hash values by converting each Uint8Array byte, which is unsigned by default,
* into a signed byte, assuming they are little endian.
* @param hash1 The hash value to compare.
* @param hash2 The hash value to compare.
* @returns Zero if the hash values are equal, otherwise return the difference of the first pair of non-matching bytes.
*/
function compareHashValues(hash1, hash2) {
if (hash1.length !== HASH_LENGTH || hash2.length !== HASH_LENGTH) {
throw new Error("Invalid hash.");
}
for (let i = hash1.length - 1; i >= 0; i--) {
const difference = (hash1[i] << 24 >> 24) - (hash2[i] << 24 >> 24);
if (difference !== 0) {
return difference;
}
}
return 0;
}
/**
* Helper method that concatenates two Uint8Array.
* @param arrays List of array to concatenate, in the order provided.
* @returns The concatenated array.
*/
function concatenate(...arrays) {
let totalLength = 0;
for (const arr of arrays) {
totalLength += arr.length;
}
const result = new Uint8Array(totalLength);
let offset = 0;
for (const arr of arrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}
function generateIonHash(ionDocBuffer) {
const hashReader = (0, ion_hash_js_1.makeHashReader)((0, ion_js_1.makeReader)(ionDocBuffer), (0, ion_hash_js_1.cryptoHasherProvider)('sha256'));
while (hashReader.next() != null) {
}
return hashReader.digest();
}
function validateRevisionHash(revisionAsJSON) {
const fcnName = "[validateRevisionHash]";
const metadata = (0, Util_1.metadataJSONtoIonUint8Array)(revisionAsJSON.metadata);
const data = (0, ion_js_1.dumpBinary)(revisionAsJSON.data);
const hash = revisionAsJSON.hash;
const metadataDigest = generateIonHash(metadata);
const dataDigest = generateIonHash(data);
const candidateHash = joinHashesPairwise(dataDigest, metadataDigest).toString('base64');
logger.debug(`${fcnName} Candidate hash generated: ${candidateHash} comparing with ${hash}`);
return candidateHash === hash;
}
exports.validateRevisionHash = validateRevisionHash;