// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/Die.java
// public static void dieIf(boolean condition, Supplier<String> message) {
//     if (condition) {
//         die(message.get());
//     }
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/Die.java
// public static void rethrow(RunnableWithOops runnable, Supplier<String> errorMessage) {
//     try {
//         runnable.run();
//     } catch (Throwable e) {
//         die(e, errorMessage.get());
//     }
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/UnderBar.java
// static <T> List<T> filter(Iterable<T> ts, Predicate<T> predicate) {
//     return stream(ts).filter(predicate).collect(toList());
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/UnderBar.java
// @SafeVarargs
// static <T> List<T> list(T... ts) {
//     return Arrays.asList(ts);
// }


import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import static com.tailoredshapes.underbar.ocho.Die.dieIf;
import static com.tailoredshapes.underbar.ocho.Die.rethrow;
import static com.tailoredshapes.underbar.ocho.UnderBar.filter;
import static com.tailoredshapes.underbar.ocho.UnderBar.list;
package com.tailoredshapes.underbar.crypto;



public interface RSA {
    static KeyPair keypair(){
        return keypair(4096);
    }

    static KeyPair keypair(int keysize){
        KeyPairGenerator generator = rethrow(()->KeyPairGenerator.getInstance("RSA"));
        generator.initialize(keysize);
        return generator.generateKeyPair();
    }

    static BigInteger readBigInteger(DataInputStream in) {
        rethrow(() -> in.read() == 2);

        int length = rethrow(() -> in.read());

        if (length >= 0x80) {
            byte[] extended = new byte[4];
            int bytesToRead = length & 0x7f;
            rethrow(() -> in.readFully(extended, 4 - bytesToRead, bytesToRead));
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/Die.java
// public static void dieIf(boolean condition, Supplier<String> message) {
//     if (condition) {
//         die(message.get());
//     }
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/Die.java
// public static void rethrow(RunnableWithOops runnable, Supplier<String> errorMessage) {
//     try {
//         runnable.run();
//     } catch (Throwable e) {
//         die(e, errorMessage.get());
//     }
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/UnderBar.java
// static <T> List<T> filter(Iterable<T> ts, Predicate<T> predicate) {
//     return stream(ts).filter(predicate).collect(toList());
// }
// 
// Path: underbar.ocho/src/main/java/com/tailoredshapes/underbar/ocho/UnderBar.java
// @SafeVarargs
// static <T> List<T> list(T... ts) {
//     return Arrays.asList(ts);
// }


// Path: underbar.crypto/src/main/java/com/tailoredshapes/underbar/crypto/RSA.java
import javax.crypto.Cipher;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import static com.tailoredshapes.underbar.ocho.Die.dieIf;
import static com.tailoredshapes.underbar.ocho.Die.rethrow;
import static com.tailoredshapes.underbar.ocho.UnderBar.filter;
import static com.tailoredshapes.underbar.ocho.UnderBar.list;

package com.tailoredshapes.underbar.crypto;



public interface RSA {
    static KeyPair keypair(){
        return keypair(4096);
    }

    static KeyPair keypair(int keysize){
        KeyPairGenerator generator = rethrow(()->KeyPairGenerator.getInstance("RSA"));
        generator.initialize(keysize);
        return generator.generateKeyPair();
    }

    static BigInteger readBigInteger(DataInputStream in) {
        rethrow(() -> in.read() == 2);

        int length = rethrow(() -> in.read());

        if (length >= 0x80) {
            byte[] extended = new byte[4];
            int bytesToRead = length & 0x7f;
            rethrow(() -> in.readFully(extended, 4 - bytesToRead, bytesToRead));
            length = new BigInteger(extended).intValue();