Repository: RustCrypto/hashes (language: rust)

Issue:
FSB produces wrong hashes.
### Description
I tested several messages for a university assignment and compared the digests to the reference implementation. For longer messages the FSB implementation produces different results.

Using the random data from https://github.com/RustCrypto/hashes/blob/master/fsb/tests/mod.rs#L15 with the reference implementation produces the hash `40b7538be5e51978690d1a92fe12a7f25f0a7f08`. The implementation of this project produces the hash `454b28a8d158ad63ff59e3f761919c7581ee78d3` for this data. Empty and small files seem to work fine and produce the same hashes.

For convenience the random data is uploaded here: [testdata.txt](https://github.com/RustCrypto/hashes/files/8418268/testdata.txt)

I am fairly new to Rust, so it is possible i somehow used this library wrongly.

I couldn't find any other FSB implementations to compare against to verify the results.

### Testing reference implementation
```bash
wget https://www.paris.inria.fr/secret/CBCrypto/fsb_reference_implementation.zip
unzip fsb_reference_implementation.zip
cd Reference_Implementation
make
./fsb -s 160 <insert path>/testdata.txt
```

### Testing this implementation
```rust
#[test]
fn fsb160_compare_to_reference_impl() {
    let mut h = Fsb160::new();
    let data = include_bytes!("<insert path>/testdata.txt");
    h.update(data);
    let hash = &h.finalize()[..];
    println!("Hash: {:02X?}", hash);
    assert_eq!(
        hash,
        &hex!("40b7538be5e51978690d1a92fe12a7f25f0a7f08")[..]
    );
}
```

### Links to reference implementation
Reference implementation: [https://www.paris.inria.fr/secret/CBCrypto/index.php?pg=fsb](https://www.paris.inria.fr/secret/CBCrypto/index.php?pg=fsb) (on the right side)
Reference implementation direct download: [https://www.paris.inria.fr/secret/CBCrypto/fsb_reference_implementation.zip](https://www.paris.inria.fr/secret/CBCrypto/fsb_reference_implementation.zip)



Discussion / hints:
Thank you for reporting this! I do not have time to properly debug this issue right now, but I will try to look into it somewhat later.

cc @iquerejeta
Thanks for sharing! The next couple of weeks I'm not at home, but I'll look into it as I get back. Curious to see what causes the fault with long messages. 

Maybe in the meantime we can put a little footnote in the README, wdyt @newpavlov?
Hi I've found smaller messages that produce different hashes. The smallest that i found is 52 bytes long for fsb160:
`45fdeca3b08e38af53d7c4c60e3ad208ce5066441036e9f191e0b75036a77f65e2eaa4752443233fbe8f8943bf956de595665c38`

Test:
```rust
#[test]
fn fsb160_compare_to_reference_impl_52() {
    let mut h = Fsb160::new();
    let data = &hex!("45fdeca3b08e38af53d7c4c60e3ad208ce5066441036e9f191e0b75036a77f65e2eaa4752443233fbe8f8943bf956de595665c38")[..];
    h.update(data);
    let hash = &h.finalize()[..];
    assert_eq!(
        hash,
        &hex!("57ff8cabced1b6992729bcc886f631a9502d62fd")[..]
    );
}
```

Fix patch:
diff --git a/fsb/src/macros.rs b/fsb/src/macros.rs
index 8b1e31a8f..7b59004cd 100644
--- a/fsb/src/macros.rs
+++ b/fsb/src/macros.rs
@@ -197,8 +197,8 @@ macro_rules! fsb_impl {
                     truncated[0] = array[starting_byte] << (bits_in_cue - shift_value as u8);
                     truncated[0] ^= array[0] >> shift_value;
                     for position in 1..Self::SIZE_OUTPUT_COMPRESS {
-                        truncated[position] ^= array[position - 1] >> (8 - shift_value);
-                        truncated[position] ^= array[position] << shift_value;
+                        truncated[position] ^= array[position - 1] << (8 - shift_value);
+                        truncated[position] ^= array[position] >> shift_value;
                     }
                 } else {
                     // First we need to decide which is the last byte and bit that will go to the first position.


Test patch:
diff --git a/fsb/tests/mod.rs b/fsb/tests/mod.rs
index bf9749450..928f1b979 100644
--- a/fsb/tests/mod.rs
+++ b/fsb/tests/mod.rs
@@ -15,7 +15,7 @@ fn fsb160_rand() {
     feed_rand_16mib(&mut h);
     assert_eq!(
         h.finalize()[..],
-        hex!("454b28a8d158ad63ff59e3f761919c7581ee78d3")[..]
+        hex!("40b7538be5e51978690d1a92fe12a7f25f0a7f08")[..]
     );
 }
 
@@ -25,7 +25,7 @@ fn fsb224_rand() {
     feed_rand_16mib(&mut h);
     assert_eq!(
         h.finalize()[..],
-        hex!("80ef345c462dc88261355eaf44ee2bb7277d01db77b46b2828a918b6")[..]
+        hex!("0ec203ccec7cbf0cadd32e5dc069d0b4215a104c4dad5444944a0d09")[..]
     );
 }
 
@@ -35,7 +35,7 @@ fn fsb256_rand() {
     feed_rand_16mib(&mut h);
     assert_eq!(
         h.finalize()[..],
-        hex!("301cbfd7031de3568bf4c4ffa86c2295bde89937acc8ee470446b8c55b88334a")[..]
+        hex!("eecb42832a2b03bc91beb1a56ddf2973c962b1aeb22f278e9d78a7a8879ebba7")[..]
     );
 }
 
@@ -47,8 +47,8 @@ fn fsb384_rand() {
     assert_eq!(
         h.finalize()[..],
         hex!("
-            d11c0ea4ef363916ad8c2a4d8b4758bf0c36e4de93f2bbaeba037b0726c83179
-            0ec4e5d9d3e9d66e0810d391a00bf60e
+            f17533ed4d4484434715e63bc8e801c9cfe988c38d47d3b4be0409571360aa2f
+            b360b2804c14f606906b323e7901c09e
         ")[..]
     );
 }
@@ -61,8 +61,8 @@ fn fsb512_rand() {
     assert_eq!(
         h.finalize()[..],
         hex!("
-            eb15b6c3626e38141e4f17b3b89d7deed007c4ae727452010601bc4e16deef82
-            f81415566defb1aba3db9b1b14746bd81cf3689a0f79e6d00434ff4ca19b3e66
+            957a7733643e075ab7a3b04607800a6208a26b008bdaee759a3a635bb9b5b708
+            3531725783505468bf438f2a0a96163bbe0775468a11c93db9994c466b2e7d8c
         ")[..]
     );
 }