/// <summary> /// Create KSI signature instance from given signature by adding a new aggregation hash chain as the lowest level chain. /// </summary> /// <param name="signature">Base KSI signature</param> /// <param name="inputHash">Input hash of the aggregation chain to be added.</param> /// <param name="aggregationAlgorithm">Aggregation algorithm of the aggregation chain to be added.</param> /// <param name="chainLinks">Hash chain links of the aggregation chain to be added.</param> /// <returns></returns> public IKsiSignature CreateSignatureWithAggregationChain(IKsiSignature signature, DataHash inputHash, HashAlgorithm aggregationAlgorithm, AggregationHashChain.Link[] chainLinks) { AggregationHashChain lowestChain = signature.GetAggregationHashChains()[0]; // create chain index ulong[] firstLevelChainIndex = lowestChain.GetChainIndex(); ulong[] chainIndex = new ulong[firstLevelChainIndex.Length + 1]; Array.Copy(firstLevelChainIndex, 0, chainIndex, 0, firstLevelChainIndex.Length); chainIndex[chainIndex.Length - 1] = AggregationHashChain.CalcLocationPointer(chainLinks); // Create new lowest chain AggregationHashChain newAggregationHashChain = new AggregationHashChain(lowestChain.AggregationTime, chainIndex, inputHash, aggregationAlgorithm.Id, chainLinks); // check level correction AggregationHashChainResult chainResult = newAggregationHashChain.GetOutputHash(new AggregationHashChainResult(0, inputHash)); ulong levelCorrection = lowestChain.GetChainLinks()[0].LevelCorrection; if (chainResult.Level > levelCorrection) { throw new KsiException(string.Format( "The aggregation hash chain cannot be added as lowest level chain. It's output level ({0}) is bigger than level correction of the first link of the first aggregation hash chain of the base signature ({1}).", chainResult.Level, levelCorrection)); } if (chainResult.Hash != lowestChain.InputHash) { throw new KsiException("The aggregation hash chain cannot be added as lowest level chain. It's output hash does not match base signature input hash."); } // Create list on new signature child tags. // Add new aggregation hash chain as the first element. // Add the chain that was initally the lowest (with corrected level correction) as second element List <ITlvTag> childTags = new List <ITlvTag> { newAggregationHashChain, CreateAggregationHashChainWithLevelCorrection(lowestChain, levelCorrection - chainResult.Level) }; foreach (ITlvTag tag in signature) { // Add all the signature components except the chain that was initially the lowest. if (!ReferenceEquals(tag, lowestChain)) { childTags.Add(tag); } } KsiSignature resultSignature = new KsiSignature(false, false, childTags.ToArray()); Verify(resultSignature, inputHash); return(resultSignature); }
/// <summary> /// Get last aggregation hash chain output hash that is calculated from all aggregation hash chains /// </summary> /// <returns>output hash</returns> public DataHash GetLastAggregationHashChainRootHash() { if (_aggregationHashChainRootHash != null) { return(_aggregationHashChainRootHash); } AggregationHashChainResult lastResult = new AggregationHashChainResult(0, _aggregationHashChains[0].InputHash); foreach (AggregationHashChain chain in _aggregationHashChains) { lastResult = chain.GetOutputHash(lastResult); } return(_aggregationHashChainRootHash = lastResult.Hash); }
/// <summary> /// Get output hash. /// </summary> /// <param name="result">last hashing result</param> /// <returns>output hash chain result</returns> public AggregationHashChainResult GetOutputHash(AggregationHashChainResult result) { if (result == null) { throw new ArgumentNullException(nameof(result)); } lock (_cacheLock) { if (_aggregationHashChainResultCache == null) { _aggregationHashChainResultCache = new Dictionary <AggregationHashChainResult, AggregationHashChainResult>(); } else if (_aggregationHashChainResultCache.ContainsKey(result)) { return(_aggregationHashChainResultCache[result]); } } DataHash lastHash = result.Hash; ulong level = result.Level; foreach (Link link in _links) { level += link.LevelCorrection + 1; if (link.Direction == LinkDirection.Left) { lastHash = GetStepHash(lastHash.Imprint, link.GetSiblingData(), level); } if (link.Direction == LinkDirection.Right) { lastHash = GetStepHash(link.GetSiblingData(), lastHash.Imprint, level); } } AggregationHashChainResult returnValue = new AggregationHashChainResult(level, lastHash); lock (_cacheLock) { _aggregationHashChainResultCache[result] = returnValue; } return(returnValue); }
/// <summary> /// Compare current object against another object. /// </summary> /// <param name="obj">object to compare with</param> /// <returns>true if objects are equal</returns> public override bool Equals(object obj) { AggregationHashChainResult a = obj as AggregationHashChainResult; // If parameter is null, return false. if (ReferenceEquals(a, null)) { return(false); } if (ReferenceEquals(this, a)) { return(true); } // If run-time types are not exactly the same, return false. if (GetType() != a.GetType()) { return(false); } return(Hash == a.Hash && Level == a.Level); }