class RxShamir {

  @Nonnull
  public Single<BigInteger> recoverSecret(
      @Nonnull final Set<Share> shares,
      @Nonnull final RecoveryScheme recoveryScheme) {
    
    checkNotNull(shares, "\'shares\' must not be null.");
    checkEachElementIsNotNull(shares, "\'shares\' must not contain null.");
    checkNotNull(recoveryScheme, "\'recoveryScheme\' must not be null.");
    
    final Single<BigInteger> secret = Observable
        .fromIterable(shares)
        .flatMapSingle(outerShare -> Observable
            .fromIterable(shares)
            .filter(innerShare -> !innerShare.equals(outerShare))
            .map(innerShare -> {
              final BigInteger indexDifferenceModInverse = innerShare
                  .getIndex()
                  .subtract(outerShare.getIndex())
                  .modInverse(recoveryScheme.getPrime());
              
              return innerShare
                  .getIndex()
                  .multiply(indexDifferenceModInverse);
            })
            .reduce(ONE, BigInteger::multiply)
            .map(value -> value.multiply(outerShare.getValue())))
        .reduce(ZERO, BigInteger::add)
        .map(workingSecret -> workingSecret.mod(recoveryScheme.getPrime()));
    
    return checkRecoveryInformation(shares, recoveryScheme).andThen(secret);
  }

  public  RxShamir(@Nonnull final SecureRandom random);

}