package uc.crypto;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import uc.DCClient;
/**
*
* A class standing for the interleave hashes of one level(in the merkletree) in one file
*
*
* @author Quicksilver
*
*/
public class InterleaveHashes {
private final List<HashValue> interleaves;
/**
* used for small files < 64 KiB
* the interleaves only consist of the root..
*
* @param root - the roothash
*/
public InterleaveHashes(HashValue root) {
interleaves = Arrays.asList(root);
}
public InterleaveHashes(ByteBuffer bbuf) {
interleaves = new ArrayList<HashValue>();
while (bbuf.hasRemaining()) {
byte[] array = new byte[TigerHashValue.digestlength];
bbuf.get(array);
interleaves.add(HashValue.createHash(array));
}
}
public InterleaveHashes getParentInterleaves() {
List<HashValue> nextValues = new ArrayList<HashValue>(interleaves.size()/2 +1);
Iterator<HashValue> it = interleaves.iterator();
while (it.hasNext()) {
HashValue first = it.next();
if (it.hasNext()) {
nextValues.add(first.internalHash(it.next()));
} else {
nextValues.add(first);
}
}
return new InterleaveHashes(nextValues);
}
/**
*
* @param interleaves - the interleaves of one level
*/
public InterleaveHashes(HashValue[] interleaves){
this.interleaves = Arrays.asList(interleaves);
}
public InterleaveHashes(List<HashValue> interleaves) {
this.interleaves = interleaves;
}
/**
* creates interleaves from a ' ' separated base32 encoded string ( toString())
* @param serilaizedInterleaves
*/
public InterleaveHashes(String serilaizedInterleaves){
String[] values = serilaizedInterleaves.split(Pattern.quote(" "));
interleaves = new ArrayList<HashValue>();
for (int i=0; i < values.length; i++) {
interleaves.add(HashValue.createHash(values[i]));
}
}
/**
*
* @return a copy
*/
public List<HashValue> copy(){
List<HashValue> ret = new ArrayList<HashValue>();
for (HashValue value: interleaves) {
ret.add(value.copy());
}
return ret;
}
/**
*
* @param roothash - root hash against which verification is done..
* @return true if the interleaves match the root hash..
*/
public boolean verify(HashValue roothash) {
return DCClient.get().getHashEngine().verifyInterleaves(this, roothash);
}
/**
* computes the granularity of the file
* meaning for how many bytes one single HashValue in this file stands for
* @param filesize - the size of the file
* @return the minimum size of verification for this file
*/
public long getGranularity(long filesize){
long gran = filesize / interleaves.size();
long roundup = 1024;
while ( roundup < gran ) {
roundup *=2;
}
return roundup;
}
public int hashValuesSize() {
return interleaves.size();
}
/**
*
* @return an array of Hashvalues.. the interleaves
*/
public List<HashValue> getInterleaves() {
return interleaves;
}
public HashValue getHashValue(int position) {
return interleaves.get(position);
}
/**
* computes the size in bytes ... needed for uploading to some client
* @return number of bytes
*/
public long byteSize() {
return interleaves.size() * TigerHashValue.digestlength;
}
public String toString(){
StringBuilder sb = new StringBuilder();
for (HashValue hv: interleaves) {
sb.append(hv.toString());
sb.append(" ");
}
return sb.substring(0, sb.length()-1);
}
}