Skip to content
Snippets Groups Projects
Commit 114ca203 authored by akwizgran's avatar akwizgran
Browse files

Tests and bugfixes for XOR encoder and decoder.

parent 74dd4e27
No related branches found
No related tags found
No related merge requests found
...@@ -4,10 +4,18 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; ...@@ -4,10 +4,18 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
class Frame { class Frame {
private final byte[] buf = new byte[MAX_FRAME_LENGTH]; private final byte[] buf;
private int length = -1; private int length = -1;
Frame() {
this(MAX_FRAME_LENGTH);
}
Frame(int length) {
buf = new byte[length];
}
public byte[] getBuffer() { public byte[] getBuffer() {
return buf; return buf;
} }
......
...@@ -36,27 +36,31 @@ class XorErasureDecoder implements ErasureDecoder { ...@@ -36,27 +36,31 @@ class XorErasureDecoder implements ErasureDecoder {
// We don't need no stinkin' parity segment // We don't need no stinkin' parity segment
for(int i = 0; i < n - 1; i++) { for(int i = 0; i < n - 1; i++) {
byte[] src = set[i].getBuffer(); byte[] src = set[i].getBuffer();
System.arraycopy(src, 0, dest, offset, length); int copyLength = Math.min(length, dest.length - offset);
System.arraycopy(src, 0, dest, offset, copyLength);
offset += length; offset += length;
} }
} else { } else {
// Reconstruct the missing segment // Reconstruct the missing segment
byte[] parity = new byte[length]; byte[] parity = new byte[length];
int missingOffset = -1; int missingOffset = -1;
for(int i = 0; i < n; i++) { for(int i = 0; i < n - 1; i++) {
if(set[i] == null) { if(set[i] == null) {
missingOffset = offset; missingOffset = offset;
} else { } else {
byte[] src = set[i].getBuffer(); byte[] src = set[i].getBuffer();
System.arraycopy(src, 0, dest, offset, length);
for(int j = 0; j < length; j++) parity[j] ^= src[j]; for(int j = 0; j < length; j++) parity[j] ^= src[j];
int copyLength = Math.min(length, dest.length - offset);
System.arraycopy(src, 0, dest, offset, copyLength);
} }
offset += length; offset += length;
} }
byte[] src = set[n - 1].getBuffer();
for(int i = 0; i < length; i++) parity[i] ^= src[i];
assert missingOffset != -1; assert missingOffset != -1;
System.arraycopy(parity, 0, dest, missingOffset, length); int copyLength = Math.min(length, dest.length - missingOffset);
System.arraycopy(parity, 0, dest, missingOffset, copyLength);
} }
assert offset == length * (n - 1);
// The frame length may not be an exact multiple of the segment length // The frame length may not be an exact multiple of the segment length
int payload = HeaderEncoder.getPayloadLength(dest); int payload = HeaderEncoder.getPayloadLength(dest);
int padding = HeaderEncoder.getPaddingLength(dest); int padding = HeaderEncoder.getPaddingLength(dest);
......
...@@ -21,8 +21,9 @@ class XorErasureEncoder implements ErasureEncoder { ...@@ -21,8 +21,9 @@ class XorErasureEncoder implements ErasureEncoder {
byte[] src = f.getBuffer(), parity = set[n - 1].getBuffer(); byte[] src = f.getBuffer(), parity = set[n - 1].getBuffer();
int offset = 0; int offset = 0;
for(int i = 0; i < n - 1; i++) { for(int i = 0; i < n - 1; i++) {
System.arraycopy(src, offset, set[i].getBuffer(), 0, length); int copyLength = Math.min(length, src.length - offset);
for(int j = 0; j < length; j++) parity[j] ^= src[offset + j]; System.arraycopy(src, offset, set[i].getBuffer(), 0, copyLength);
for(int j = 0; j < copyLength; j++) parity[j] ^= src[offset + j];
offset += length; offset += length;
} }
return set; return set;
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
<test name='net.sf.briar.transport.IncomingSegmentedEncryptionLayerTest'/> <test name='net.sf.briar.transport.IncomingSegmentedEncryptionLayerTest'/>
<test name='net.sf.briar.transport.OutgoingEncryptionLayerImplTest'/> <test name='net.sf.briar.transport.OutgoingEncryptionLayerImplTest'/>
<test name='net.sf.briar.transport.OutgoingSegmentedEncryptionLayerTest'/> <test name='net.sf.briar.transport.OutgoingSegmentedEncryptionLayerTest'/>
<test name='net.sf.briar.transport.XorErasureCodeTest'/>
<test name='net.sf.briar.transport.XorErasureDecoderTest'/> <test name='net.sf.briar.transport.XorErasureDecoderTest'/>
<test name='net.sf.briar.transport.XorErasureEncoderTest'/> <test name='net.sf.briar.transport.XorErasureEncoderTest'/>
<test name='net.sf.briar.util.ByteUtilsTest'/> <test name='net.sf.briar.util.ByteUtilsTest'/>
......
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
import java.util.Random;
import net.sf.briar.BriarTestCase;
import net.sf.briar.api.transport.Segment;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Test;
public class XorErasureCodeTest extends BriarTestCase {
@Test
public void testEncodingAndDecodingWithAllSegments() throws Exception {
XorErasureEncoder e = new XorErasureEncoder(5);
XorErasureDecoder d = new XorErasureDecoder(5);
Frame f = new Frame(1234);
new Random().nextBytes(f.getBuffer());
int payload = 1234 - FRAME_HEADER_LENGTH - MAC_LENGTH;
HeaderEncoder.encodeHeader(f.getBuffer(), 0L, payload, 0);
f.setLength(1234);
Segment[] set = e.encodeFrame(f);
assertEquals(5, set.length);
Frame f1 = new Frame(1234);
assertTrue(d.decodeFrame(f1, set));
assertArrayEquals(f.getBuffer(), f1.getBuffer());
}
@Test
public void testEncodingAndDecodingWithMissingSegment() throws Exception {
XorErasureEncoder e = new XorErasureEncoder(5);
XorErasureDecoder d = new XorErasureDecoder(5);
Frame f = new Frame(1234);
new Random().nextBytes(f.getBuffer());
int payload = 1234 - FRAME_HEADER_LENGTH - MAC_LENGTH;
HeaderEncoder.encodeHeader(f.getBuffer(), 0L, payload, 0);
f.setLength(1234);
for(int i = 0; i < 5; i++) {
Segment[] set = e.encodeFrame(f);
assertEquals(5, set.length);
set[i] = null;
Frame f1 = new Frame(1234);
assertTrue(d.decodeFrame(f1, set));
assertArrayEquals(f.getBuffer(), f1.getBuffer());
}
}
}
...@@ -14,24 +14,15 @@ public class XorErasureDecoderTest extends BriarTestCase { ...@@ -14,24 +14,15 @@ public class XorErasureDecoderTest extends BriarTestCase {
@Test @Test
public void testMaximumLength() throws Exception { public void testMaximumLength() throws Exception {
XorErasureDecoder d = new XorErasureDecoder(5);
// A frame of the maximum length should be decoded successfully // A frame of the maximum length should be decoded successfully
Segment[] set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4, 5); Segment[] set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4, 5);
XorErasureDecoder d = new XorErasureDecoder(5);
Frame f = new Frame(); Frame f = new Frame();
assertTrue(d.decodeFrame(f, set)); assertTrue(d.decodeFrame(f, set));
// Check the header checkFrame(f, MAX_FRAME_LENGTH);
byte[] b = f.getBuffer();
assertEquals(0L, HeaderEncoder.getFrameNumber(b));
int payload = MAX_FRAME_LENGTH - FRAME_HEADER_LENGTH - MAC_LENGTH;
assertEquals(payload, HeaderEncoder.getPayloadLength(b));
assertEquals(0, HeaderEncoder.getPaddingLength(b));
// Check the body
assertEquals(MAX_FRAME_LENGTH, f.getLength());
for(int i = FRAME_HEADER_LENGTH; i < MAX_FRAME_LENGTH; i++) {
assertEquals(0, b[i]);
}
// A frame larger than the maximum length should not be decoded // A frame larger than the maximum length should not be decoded
set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4 + 1, 5); set = encodeEmptyFrame(MAX_FRAME_LENGTH / 4 + 1, 5);
f = new Frame();
try { try {
d.decodeFrame(f, set); d.decodeFrame(f, set);
} catch(FormatException expected) {} } catch(FormatException expected) {}
...@@ -47,12 +38,35 @@ public class XorErasureDecoderTest extends BriarTestCase { ...@@ -47,12 +38,35 @@ public class XorErasureDecoderTest extends BriarTestCase {
set[1].setLength(251); set[1].setLength(251);
// The frame should be decoded successfully // The frame should be decoded successfully
XorErasureDecoder d = new XorErasureDecoder(4); XorErasureDecoder d = new XorErasureDecoder(4);
Frame f = new Frame(); Frame f = new Frame(750);
assertTrue(d.decodeFrame(f, set)); assertTrue(d.decodeFrame(f, set));
// The minimum of the segments' lengths should have been used // The minimum of the segments' lengths should have been used
assertEquals(750, f.getLength()); assertEquals(750, f.getLength());
} }
@Test
public void testDecodingWithMissingSegment() throws Exception {
XorErasureDecoder d = new XorErasureDecoder(4);
for(int i = 0; i < 4; i++) {
Segment[] set = encodeEmptyFrame(250, 4);
set[i] = null;
// The frame should be decoded successfully
Frame f = new Frame(750);
assertTrue(d.decodeFrame(f, set));
checkFrame(f, 750);
}
}
@Test
public void testDecodingWithTwoMissingSegments() throws Exception {
XorErasureDecoder d = new XorErasureDecoder(4);
Segment[] set = encodeEmptyFrame(250, 4);
set[0] = null;
set[1] = null;
Frame f = new Frame(750);
assertFalse(d.decodeFrame(f, set));
}
private Segment[] encodeEmptyFrame(int length, int n) { private Segment[] encodeEmptyFrame(int length, int n) {
Segment[] set = new Segment[n]; Segment[] set = new Segment[n];
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
...@@ -64,4 +78,17 @@ public class XorErasureDecoderTest extends BriarTestCase { ...@@ -64,4 +78,17 @@ public class XorErasureDecoderTest extends BriarTestCase {
HeaderEncoder.encodeHeader(set[n - 1].getBuffer(), 0L, payload, 0); HeaderEncoder.encodeHeader(set[n - 1].getBuffer(), 0L, payload, 0);
return set; return set;
} }
private void checkFrame(Frame f, int length) {
byte[] b = f.getBuffer();
assertEquals(0L, HeaderEncoder.getFrameNumber(b));
int payload = length - FRAME_HEADER_LENGTH - MAC_LENGTH;
assertEquals(payload, HeaderEncoder.getPayloadLength(b));
assertEquals(0, HeaderEncoder.getPaddingLength(b));
// Check the body
assertEquals(length, f.getLength());
for(int i = FRAME_HEADER_LENGTH; i < length; i++) {
assertEquals("" + i, 0, b[i]);
}
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment