// Path: src/main/java/at/archistar/crypto/data/Share.java
// public interface Share extends Comparable<Share> {
// 
//     /** on-disk version of the share */
//     int VERSION = 5;
// 
//     static void writeMap(DataOutputStream sout, Map<Byte, byte[]> map) throws IOException {
//         sout.writeInt(map.size());
//         for (Map.Entry<Byte, byte[]> e : map.entrySet()) {
//             Byte key = e.getKey();
//             byte[] value = e.getValue();
// 
//             sout.writeByte(key);
//             sout.writeInt(value.length);
//             sout.write(value);
//         }
//     }
// 
//     /**
//      * @return the share's X-value (same as id)
//      */
//     int getX();
// 
//     /**
//      * @return the share's id (same as x-value)
//      */
//     byte getId();
// 
//     /**
//      * @return the share's main body (y-values)
//      */
//     @SuppressFBWarnings("EI_EXPOSE_REP")
//     byte[] getYValues();
// 
//     /**
//      * This returns a serialized form of the content (plus IC info) of the share.
//      *
//      * @return the share's byte[] representation containing all information
//      * @throws IOException
//      */
//     byte[] getSerializedData() throws IOException;
// 
//     /**
//      * This returns a Map of the metadata that are common to all share types;
//      * the idea is that the getMetaData()-implementations in all the share types
//      * first get this Map and then add their own special keys
//      *
//      * @return the metadata that are common to all shares
//      */
//     default HashMap<String, String> getCommonMetaData() {
//         HashMap<String, String> res = new HashMap<>();
//         res.put("archistar-share-type", getShareType());
//         res.put("archistar-version", Integer.toString(VERSION));
//         res.put("archistar-id", Byte.toString(getId()));
//         res.put("archistar-length", Integer.toString(getYValues().length));
//         return res;
//     }
// 
//     /**
//      * @return the (internal) metadata of a share necessary for reconstruction
//      */
//     HashMap<String, String> getMetaData();
// 
//     /**
//      * compare two shares
//      *
//      * @param t the share to be compared
//      * @return +/-1 if different, 0 if same
//      */
//     @Override
//     default int compareTo(Share t) {
// 
//         try {
//             if (Arrays.equals(getSerializedData(), t.getSerializedData())) {
//                 return 0;
//             } else {
//                 return t.getId()- getId();
//             }
//         } catch (IOException ex) {
//             return t.getId() - getId();
//         }
//     }
// 
//     /**
//      * @return a String representation of the type of the share
//      */
//     String getShareType();
// 
//     /**
//      * @return the length of the original file
//      */
//     int getOriginalLength();
// }


import at.archistar.crypto.data.Share;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
package at.archistar.crypto.secretsharing;



/**
 * <p>This is the abstract base class for all Secret-Sharing algorithms.</p>
 *
 * <p><i>Secret Sharing</i> means splitting up some secret (for example a message) in <i>n</i> pieces such that any number of
 * at least <i>k</i> pieces can reconstruct the secret, but <i>k - 1</i> pieces yield absolutely no information about the
 * secret.</p>
 *
 * For detailed information, see:
 * <a href="http://en.wikipedia.org/wiki/Secret_sharing">http://en.wikipedia.org/wiki/Secret_sharing</a>
 */
abstract class BaseSecretSharing implements SecretSharing {

    /** number of shares */
    protected final int n;

    /** minimum number of valid shares required for reconstruction */
    protected final int k;

    /**
     * Constructor (can and should only be called from sub-classes)
     *
     * @param n the number of shares to create
     * @param k the minimum number of valid shares required for reconstruction
     * @throws WeakSecurityException if the scheme is not secure for the given parameters
     */
    protected BaseSecretSharing(int n, int k) throws WeakSecurityException {
        checkSecurity(n, k); // validate security

        this.n = n;
        this.k = k;
    }

    /**
     * Checks if this Secret-Sharing scheme is secure enough for the given parameters.<br>
     * (throws a WeakSecurityException if this is the case)
     *
     * @param n the number of shares to create
     * @param k the minimum number of valid shares required for reconstruction
     * @throws WeakSecurityException thrown if the Secret-Sharing scheme is not secure enough
     */
    protected static void checkSecurity(int n, int k) throws WeakSecurityException { // n is there in case we want to override this
        if (k < 2) {
            throw new WeakSecurityException("Parameter \"k\" has to be at least 2");
        }
    }

    /**
     * Checks if there are enough shares for reconstruction.<br>
     * <i>(This method assumes all shares to be valid!)</i>
     *
     * @param n the number of shares to reconstruct from
     * @param k the minimum number of valid shares required for reconstruction
     * @return true if there are enough shares; false otherwise
     */
    protected static boolean validateShareCount(int n, int k) {
        return n >= k; // base implementation; necessary condition for every Secret-Sharing scheme
    }

    /**
     * Returns the ids of the shares missing from the given set
     *
     * @param shares the given shares
     * @return the ids of the missing shares
     */
// Path: src/main/java/at/archistar/crypto/data/Share.java
// public interface Share extends Comparable<Share> {
// 
//     /** on-disk version of the share */
//     int VERSION = 5;
// 
//     static void writeMap(DataOutputStream sout, Map<Byte, byte[]> map) throws IOException {
//         sout.writeInt(map.size());
//         for (Map.Entry<Byte, byte[]> e : map.entrySet()) {
//             Byte key = e.getKey();
//             byte[] value = e.getValue();
// 
//             sout.writeByte(key);
//             sout.writeInt(value.length);
//             sout.write(value);
//         }
//     }
// 
//     /**
//      * @return the share's X-value (same as id)
//      */
//     int getX();
// 
//     /**
//      * @return the share's id (same as x-value)
//      */
//     byte getId();
// 
//     /**
//      * @return the share's main body (y-values)
//      */
//     @SuppressFBWarnings("EI_EXPOSE_REP")
//     byte[] getYValues();
// 
//     /**
//      * This returns a serialized form of the content (plus IC info) of the share.
//      *
//      * @return the share's byte[] representation containing all information
//      * @throws IOException
//      */
//     byte[] getSerializedData() throws IOException;
// 
//     /**
//      * This returns a Map of the metadata that are common to all share types;
//      * the idea is that the getMetaData()-implementations in all the share types
//      * first get this Map and then add their own special keys
//      *
//      * @return the metadata that are common to all shares
//      */
//     default HashMap<String, String> getCommonMetaData() {
//         HashMap<String, String> res = new HashMap<>();
//         res.put("archistar-share-type", getShareType());
//         res.put("archistar-version", Integer.toString(VERSION));
//         res.put("archistar-id", Byte.toString(getId()));
//         res.put("archistar-length", Integer.toString(getYValues().length));
//         return res;
//     }
// 
//     /**
//      * @return the (internal) metadata of a share necessary for reconstruction
//      */
//     HashMap<String, String> getMetaData();
// 
//     /**
//      * compare two shares
//      *
//      * @param t the share to be compared
//      * @return +/-1 if different, 0 if same
//      */
//     @Override
//     default int compareTo(Share t) {
// 
//         try {
//             if (Arrays.equals(getSerializedData(), t.getSerializedData())) {
//                 return 0;
//             } else {
//                 return t.getId()- getId();
//             }
//         } catch (IOException ex) {
//             return t.getId() - getId();
//         }
//     }
// 
//     /**
//      * @return a String representation of the type of the share
//      */
//     String getShareType();
// 
//     /**
//      * @return the length of the original file
//      */
//     int getOriginalLength();
// }


// Path: src/main/java/at/archistar/crypto/secretsharing/BaseSecretSharing.java
import at.archistar.crypto.data.Share;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

package at.archistar.crypto.secretsharing;



/**
 * <p>This is the abstract base class for all Secret-Sharing algorithms.</p>
 *
 * <p><i>Secret Sharing</i> means splitting up some secret (for example a message) in <i>n</i> pieces such that any number of
 * at least <i>k</i> pieces can reconstruct the secret, but <i>k - 1</i> pieces yield absolutely no information about the
 * secret.</p>
 *
 * For detailed information, see:
 * <a href="http://en.wikipedia.org/wiki/Secret_sharing">http://en.wikipedia.org/wiki/Secret_sharing</a>
 */
abstract class BaseSecretSharing implements SecretSharing {

    /** number of shares */
    protected final int n;

    /** minimum number of valid shares required for reconstruction */
    protected final int k;

    /**
     * Constructor (can and should only be called from sub-classes)
     *
     * @param n the number of shares to create
     * @param k the minimum number of valid shares required for reconstruction
     * @throws WeakSecurityException if the scheme is not secure for the given parameters
     */
    protected BaseSecretSharing(int n, int k) throws WeakSecurityException {
        checkSecurity(n, k); // validate security

        this.n = n;
        this.k = k;
    }

    /**
     * Checks if this Secret-Sharing scheme is secure enough for the given parameters.<br>
     * (throws a WeakSecurityException if this is the case)
     *
     * @param n the number of shares to create
     * @param k the minimum number of valid shares required for reconstruction
     * @throws WeakSecurityException thrown if the Secret-Sharing scheme is not secure enough
     */
    protected static void checkSecurity(int n, int k) throws WeakSecurityException { // n is there in case we want to override this
        if (k < 2) {
            throw new WeakSecurityException("Parameter \"k\" has to be at least 2");
        }
    }

    /**
     * Checks if there are enough shares for reconstruction.<br>
     * <i>(This method assumes all shares to be valid!)</i>
     *
     * @param n the number of shares to reconstruct from
     * @param k the minimum number of valid shares required for reconstruction
     * @return true if there are enough shares; false otherwise
     */
    protected static boolean validateShareCount(int n, int k) {
        return n >= k; // base implementation; necessary condition for every Secret-Sharing scheme
    }

    /**
     * Returns the ids of the shares missing from the given set
     *
     * @param shares the given shares
     * @return the ids of the missing shares
     */
    byte[] determineMissingShares(Share[] shares) {