Description
Hi! Thank you for creating this library. It seems very useful. I was playing around with the example in the README and playing with corrupting the data.
Eventually I succeeded at corrupting it enough that it would not recover, but it would also not error, thus recovering faulty data... Try this:
package main
import (
"fmt"
"github.com/vivint/infectious"
)
func main() {
const (
required = 8
total = 14
)
// Create a *FEC, which will require required pieces for reconstruction at
// minimum, and generate total total pieces.
f, err := infectious.NewFEC(required, total)
if err != nil {
panic(err)
}
// Prepare to receive the shares of encoded data.
shares := make([]infectious.Share, total)
output := func(s infectious.Share) {
// the memory in s gets reused, so we need to make a deep copy
shares[s.Number] = s.DeepCopy()
}
// the data to encode must be padded to a multiple of required, hence the
// underscores.
text := "hello, world! __"
err = f.Encode([]byte(text), output)
if err != nil {
panic(err)
}
fmt.Println("----------------")
fmt.Println("Generated shares:")
// we now have total shares.
for _, share := range shares {
fmt.Printf("%d: %#v\n", share.Number, string(share.Data))
}
// Let's reconstitute with shares 0-5 missing and 1 piece corrupted.
shares = shares[6:]
shares[2].Data[1] = '!' // mutate some data
fmt.Println("----------------")
fmt.Println("Fucked shares:")
for _, share := range shares {
fmt.Printf("%d: %#v\n", share.Number, string(share.Data))
}
err = f.Correct(shares)
if err != nil {
panic(err)
}
result, err := f.Decode(nil, shares)
if err != nil {
panic(err)
}
// we have the original data!
fmt.Println("----------------")
fmt.Println("Fixed shares:")
fmt.Printf("original text: %#v\n", string(text))
fmt.Printf("recovered text: %#v\n", string(result))
}
You can try the snippet above in the playground: https://play.golang.org/p/ueV5p2O6QE5
It does not panic at all; printing:
----------------
Generated shares:
0: "he"
1: "ll"
2: "o,"
3: " w"
4: "or"
5: "ld"
6: "! "
7: "__"
8: " n"
9: "P\\"
10: "\xceS"
11: "\xf28"
12: "\x94\xdc"
13: "\xd9y"
----------------
Fucked shares:
6: "! "
7: "__"
8: " !"
9: "P\\"
10: "\xceS"
11: "\xf28"
12: "\x94\xdc"
13: "\xd9y"
----------------
Fixed shares:
original text: "hello, world! __"
recovered text: "h`l\x84oR \xd0o\xfdl\xfd! __"
In this example I require 8 "good" shares to recover. I have 8 shares, but 1 of them is corrupt, so technically I only have 7 good shares, which is not enough to decode this... yet no panic.
That's weird, no? I guess there's something I'm not understanding but I would have expected an error value if the data was too corrupt.
Now if I replace:
// Let's reconstitute with shares 0-5 missing and 1 piece corrupted.
shares = shares[6:]
shares[2].Data[1] = '!' // mutate some data
...with a few mutations too many:
// Let's corrupt shares 0-3 through mutation:
shares[0].Data[1] = '!'
shares[1].Data[1] = '!'
shares[2].Data[1] = '!'
shares[3].Data[1] = '!'
I get: panic: too many errors to reconstruct
which is the kind of error I'd expect to get with my first snippet instead of decoding garbage data.
Is it a bug? or a weird edge case where the algorithm breaks?