aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sleep_register.rs64
1 files changed, 47 insertions, 17 deletions
diff --git a/src/sleep_register.rs b/src/sleep_register.rs
index fa8229d..6041210 100644
--- a/src/sleep_register.rs
+++ b/src/sleep_register.rs
@@ -78,24 +78,25 @@ impl HyperRegister {
buf
}
- pub fn hash_roots(reg: &mut HyperRegister, index: u64) -> Result<Vec<u8>> {
- let mut buf = [0; 40];
+ /// Hashes all the tree root parents for the given entry index (data index, not tree index).
+ pub fn hash_roots(reg: &mut HyperRegister, entry_index: u64) -> Result<Vec<u8>> {
+ let mut buf = [0; 32];
let mut hash = Blake2b::new(32);
let mut index_buf = [0; 8];
hash.input(&[2; 1]);
- for ri in HyperRegister::tree_root_nodes(index) {
+ for ri in HyperRegister::tree_root_nodes(entry_index) {
u64::to_be(ri).encode_fixed(&mut index_buf);
let node = reg.get_tree_entry(ri)?;
hash.input(&node[0..32]);
hash.input(&index_buf);
hash.input(&node[32..40]);
}
- hash.result(&mut buf[0..32]);
+ hash.result(&mut buf);
Ok(buf.to_vec())
}
+ /// Calculates the root notes for a given length (of data entries, not tree entries)
fn tree_root_nodes(data_count: u64) -> Vec<u64> {
- // Calculates the root notes for a given length (of data entries, not tree entries)
// TODO: this should be an iterator
// NB: this is a relatively "hot" function, gets called (repeatedly?) on every mutation,
// and potentially in inner loops of lookups.
@@ -124,11 +125,13 @@ impl HyperRegister {
roots
}
- pub fn get_data_offset(reg: &mut HyperRegister, index: u64) -> Result<u64> {
+ /// Finds the offset of the given data chunk in the linear appended data file (not a "checked
+ /// out" individual file)
+ pub fn get_data_offset(reg: &mut HyperRegister, entry_index: u64) -> Result<u64> {
// TODO: this is a naive (linear) implementation
// log(N) would go up previous parent nodes (eg, use root_nodes())
let mut sum: u64 = 0;
- for i in 0..index {
+ for i in 0..entry_index {
let leaf = reg.get_tree_entry(i * 2)?;
sum += u64::from_be(FixedInt::decode_fixed(&leaf[32..40]));
}
@@ -137,29 +140,29 @@ impl HyperRegister {
/// Every node has a parent, so this function won't fail unless index is over 2^62, in which
/// case it would overflow and panics instead.
- fn tree_parent_index(index: u64) -> u64 {
+ fn tree_parent_index(tree_index: u64) -> u64 {
for i in 0..62 {
// find lowest-significant zero bit
- if (index & (1 << i)) == 0 {
+ if (tree_index & (1 << i)) == 0 {
// set that bit and clear next higher
- return ((index | (1 << i))) & !(1 << (i + 1));
+ return ((tree_index | (1 << i))) & !(1 << (i + 1));
}
}
panic!("Parent lookup overflowed, huge index!");
}
/// Calling this on a leaf node is an error, as is calling very high node numbers (> 2^62)
- fn tree_child_indices(index: u64) -> Result<(u64, u64)> {
- if index % 2 == 0 {
+ fn tree_child_indices(tree_index: u64) -> Result<(u64, u64)> {
+ if tree_index % 2 == 0 {
bail!("Leaf tree nodes have no children");
}
for i in 0..62 {
// find lowest-significant zero bit...
- if (index & (1 << i)) == 0 {
+ if (tree_index & (1 << i)) == 0 {
// larger child has this bit high, next lower bit cleared
- let right = ((index | (1 << i))) & !(1 << (i - 1));
+ let right = ((tree_index | (1 << i))) & !(1 << (i - 1));
// smaller child has next lower bit cleared
- let left = index & !(1 << (i - 1));
+ let left = tree_index & !(1 << (i - 1));
return Ok((left, right));
}
}
@@ -437,7 +440,7 @@ impl HyperRegister for SleepDirRegister {
}
// 4. Add signature to signature file
- let root_hash = HyperRegister::hash_roots(self, index + 1)?;
+ let root_hash = HyperRegister::hash_roots(self, index)?;
let root_sig = ed25519::signature(&root_hash, &self.secret_key.clone().unwrap());
self.sign_sleep.append(&root_sig)?;
@@ -469,7 +472,32 @@ impl HyperRegister for SleepDirRegister {
}
fn verify(&mut self) -> Result<()> {
- unimplemented!()
+ for i in 0..self.len()? {
+
+ if let Some(_) = self.data_file {
+ // 1. Read and hash data
+ let data_chunk = self.get_data_entry(i)?;
+ let leaf_recalc = HyperRegister::hash_leaf(&data_chunk);
+
+ // 2. Check tree leaf hash for this chunk
+ let leaf = self.get_tree_entry(i * 2)?;
+ if leaf.to_vec() != leaf_recalc.to_vec() {
+ bail!("Data chunk {} failed verification (leaf hash)", i);
+ }
+ } else {
+ warn!("No simple datafile, can't verify hashes");
+ }
+
+ // 3. Recurse up parents, hashing all parents
+ let rehash = HyperRegister::hash_roots(self, i)?;
+
+ // 4. Read and verify signature in file
+ let sig = self.sign_sleep.read(i)?;
+ if !ed25519::verify(&rehash, &self.pub_key, &sig) {
+ bail!("Failed to verify signature for chunk {}", i)
+ }
+ }
+ Ok(())
}
fn check(&mut self) -> Result<()> {
@@ -532,6 +560,7 @@ fn test_sdr_append() {
sdr.append("hello world!".as_bytes()).unwrap();
sdr.check().unwrap();
+ sdr.verify().unwrap();
assert_eq!(sdr.len().unwrap(), 1);
assert_eq!(sdr.len_bytes().unwrap(), 12);
let count = 100; // TODO: make this >1000 when things are faster
@@ -539,6 +568,7 @@ fn test_sdr_append() {
sdr.append(&[1, 2, 3, 4, 5]).unwrap();
}
sdr.check().unwrap();
+ sdr.verify().unwrap();
assert_eq!(sdr.len().unwrap(), 1 + count);
assert_eq!(sdr.len_bytes().unwrap(), 12 + (count * 5));
}