/** * Complete the Eklundh algorithm for transposing with initial blocks of 8 bits. That is, assuming * all blocks of 8 bits have already been transposed * * @param input The matrix to transpose. Represented in row-major */ private static void doEklundh(List<byte[]> input) { int rows = input.size(); int byteColumns = input.get(0).length; for (int blockSize = 1; blockSize <= byteColumns / 2; blockSize = blockSize * 2) { for (int i = 0; i < rows; i = i + 2 * Byte.SIZE * blockSize) { for (int j = 0; j < byteColumns; j = j + 2 * blockSize) { // swap the blocks swap(input, i, j, blockSize); } } } }
/** * Transpose all 8 bit squares in a square matrix, in-place. * * @param input The input */ private static void transposeAllByteBlocks(List<byte[]> input) { // Start by transposing one byte and 8 rows at a time using the trivial // O(n^2) algorithm for (int i = 0; i < input.size(); i = i + Byte.SIZE) { for (int j = 0; j < input.get(0).length * Byte.SIZE; j = j + Byte.SIZE) { transposeByteBlock(input, i, j); } } }
/** * Transposes, in-place, a matrix represent in row-major as a list of byte arrays. * * @param input The matrix to transpose */ public static List<StrictBitVector> transpose(List<StrictBitVector> input) { // Ensure the is correctly formed doSanityCheck(input); int minDim = Math.min(input.get(0).getSize(), input.size()); int maxDim = Math.max(input.get(0).getSize(), input.size()); // Check if the matrix is tall boolean tall = minDim == input.get(0).getSize(); int rows = tall ? minDim : maxDim; int columns = tall ? maxDim : minDim; byte[][] res = new byte[rows][columns / Byte.SIZE]; // Process all squares of minDim x minDim List<List<byte[]>> squares = IntStream.range(0, maxDim / minDim).parallel() .mapToObj(i -> extractSquare(input, minDim, tall, i)).map(m -> { transposeAllByteBlocks(m); return m; }).map(m -> { doEklundh(m); return m; }).collect(Collectors.toList()); IntStream.range(0, maxDim / minDim).parallel() .forEach(i -> insertSquare(res, squares.get(i), minDim, tall, i)); return IntStream.range(0, res.length).parallel().mapToObj(i -> res[i]).map(StrictBitVector::new) .collect(Collectors.toList()); }
/** * Constructs a new batch of correlated OTs with errors. * * @param size Amount of OTs to construct */ public List<StrictBitVector> extend(int size) { if (size < 1) { throw new IllegalArgumentException("The amount of OTs must be a positive integer"); } if (size % Byte.SIZE != 0) { throw new IllegalArgumentException( "The amount of OTs must be a positive integer divisible by 8"); } int bytesNeeded = size / Byte.SIZE; final List<StrictBitVector> tlist = prgs.parallelStream() .limit(resources.getComputationalSecurityParameter()) .map(drbg -> { byte[] bytes = new byte[bytesNeeded]; drbg.nextBytes(bytes); return bytes; }) .map(StrictBitVector::new) .collect(Collectors.toList()); final List<StrictBitVector> ulist = receiveList(resources.getComputationalSecurityParameter()); IntStream.range(0, resources.getComputationalSecurityParameter()).parallel() .filter(i -> otChoices.getBit(i, false)) .forEach(i -> tlist.get(i).xor(ulist.get(i))); return Transpose.transpose(tlist); }
.forEach(i -> ulist.get(i).xor(tlistZero.get(i))); sendList(ulist); return Transpose.transpose(tlistZero);