Skip to content

Commit

Permalink
Merge pull request #14 from altrsoftware/feat.no-string-allocs
Browse files Browse the repository at this point in the history
Feat.no string allocs
  • Loading branch information
bschoening authored Nov 19, 2024
2 parents 4a959d7 + 855ccb9 commit dd5d3ac
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 47 deletions.
61 changes: 31 additions & 30 deletions src/main/java/com/privacylogistics/FF3Cipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,11 @@ public String encrypt(String plaintext, byte[] tweak) throws BadPaddingException
int v = n - u;

// Split the message
String A = plaintext.substring(0, u);
String B = plaintext.substring(u);
char[] A = new char[u];
char[] B = new char[v];
plaintext.getChars(0, u, A, 0);
plaintext.getChars(u, plaintext.length(), B, 0);

logger.trace("r {} A {} B {}", this.radix, A, B);

if ((tweak.length != TWEAK_LEN) && (tweak.length != TWEAK_LEN_NEW)) {
Expand Down Expand Up @@ -241,7 +244,7 @@ public String encrypt(String plaintext, byte[] tweak) throws BadPaddingException
BigInteger y = new BigInteger(byteArrayToHexString(S), 16);

// Calculate c
c = decode_int(reverseString(A), alphabet);
c = decode_int_r(A, alphabet);

c = c.add(y);

Expand All @@ -253,14 +256,14 @@ public String encrypt(String plaintext, byte[] tweak) throws BadPaddingException

logger.trace("\tm: {} A: {} c: {} y: {}", m, A, c, y);

String C = encode_int_r(c, this.alphabet, m);
char[] C = encode_int_r(c, this.alphabet, m);

// Final steps
A = B;
B = C;
logger.trace("A: {} B: {}", A, B);
}
return A + B;
return new String(A) + new String(B);
}

/**
Expand Down Expand Up @@ -309,8 +312,10 @@ public String decrypt(String ciphertext, byte[] tweak) throws BadPaddingExceptio
int v = n - u;

// Split the message
String A = ciphertext.substring(0, u);
String B = ciphertext.substring(u);
char[] A = new char[u];
char[] B = new char[v];
ciphertext.getChars(0, u, A, 0);
ciphertext.getChars(u, ciphertext.length(), B, 0);

if ((tweak.length != TWEAK_LEN) && (tweak.length != TWEAK_LEN_NEW)) {
throw new IllegalArgumentException(String.format("tweak length %d is invalid: tweak must be 56 or 64 bits",
Expand Down Expand Up @@ -363,7 +368,7 @@ public String decrypt(String ciphertext, byte[] tweak) throws BadPaddingExceptio
BigInteger y = new BigInteger(byteArrayToHexString(S), 16);

// Calculate c
c = decode_int(reverseString(B), alphabet);
c = decode_int_r(B, alphabet);

c = c.subtract(y);

Expand All @@ -375,14 +380,14 @@ public String decrypt(String ciphertext, byte[] tweak) throws BadPaddingExceptio

logger.trace("\tm: {} B: {} c: {} y: {}", m, B, c, y);

String C = encode_int_r(c, this.alphabet, m);
char[] C = encode_int_r(c, this.alphabet, m);

// Final steps
B = A;
A = C;
logger.trace("A: {} B: {}", A, B);
}
return A + B;
return new String(A) + new String(B);
}

/**
Expand Down Expand Up @@ -413,7 +418,7 @@ protected static byte[] calculateTweak64_FF3_1(byte[] tweak56)
* @param B a string value
* @return a byte array
*/
protected static byte[] calculateP(int i, String alphabet, byte[] W, String B) {
protected static byte[] calculateP(int i, String alphabet, byte[] W, char[] B) {

byte[] P = new byte[BLOCK_SIZE]; // P is always 16 bytes, zero initialized

Expand All @@ -428,8 +433,7 @@ protected static byte[] calculateP(int i, String alphabet, byte[] W, String B) {

// The remaining 12 bytes of P are copied from reverse(B) with padding

B = reverseString(B);
byte[] bBytes = decode_int(B, alphabet).toByteArray();
byte[] bBytes = decode_int_r(B, alphabet).toByteArray();

System.arraycopy(bBytes, 0, P, (BLOCK_SIZE - bBytes.length), bBytes.length);
logger.trace("round: {} W: {} P: {}", () -> i, () -> byteArrayToHexString(W), () -> byteArrayToIntString(P));
Expand Down Expand Up @@ -496,9 +500,9 @@ protected static String byteArrayToIntString(byte[] byteArray) {
}

/**
* Return a string representation of a number in the given base system
* - the string is right padded with zeros to length
* - the string is returned in reversed order expected by the calling cryptographic function
* Return a char[] representation of a number in the given base system
* - the char[] is right padded with zeros to length
* - the char[] is returned in reversed order expected by the calling cryptographic function
* i.e., the decimal value 123 in five decimal places would be '32100'
*
* examples:
Expand All @@ -507,9 +511,9 @@ protected static String byteArrayToIntString(byte[] byteArray) {
* @param n the integer number
* @param alphabet the alphabet used for encoding
* @param length the length used for padding the output string
* @return a string encoding of the number
* @return a char[] encoding of the number
*/
protected static String encode_int_r(BigInteger n, String alphabet, int length) {
protected static char[] encode_int_r(BigInteger n, String alphabet, int length) {

char[] x = new char[length];
int i=0;
Expand All @@ -526,25 +530,22 @@ protected static String encode_int_r(BigInteger n, String alphabet, int length)
while (i < length) {
x[i++] = alphabet.charAt(0);
}
return new String(x);
return x;
}

/**
* Decode a base X string representation into an integer
* @param str the original string
* Decode a base X char[] representation into an integer.
* - the BigInteger is returned in reversed order expected by the calling cryptographic function
* @param str the original char[]
* @param alphabet the alphabet and radix (len(alphabet)) for decoding
* @return an integer value of the encoded string
* @return an integer value of the encoded char[]
*/
protected static BigInteger decode_int(String str, String alphabet) {

int strlen = str.length();
protected static BigInteger decode_int_r(char[] str, String alphabet) {
BigInteger base = BigInteger.valueOf(alphabet.length());
BigInteger num = BigInteger.ZERO;
int idx =0;
for (char each : str.toCharArray()) {
int exponent = (strlen - (idx + 1));
num = num.add(base.pow(exponent).multiply(BigInteger.valueOf(alphabet.indexOf(each))));
idx += 1;
for (int i = 0; i < str.length; i++) {
char ch = str[i];
num = num.add(base.pow(i).multiply(BigInteger.valueOf(alphabet.indexOf(ch))));
}
return num;
}
Expand Down
30 changes: 13 additions & 17 deletions src/test/java/com/privacylogistics/FF3CipherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,12 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre;

import static com.privacylogistics.FF3Cipher.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.condition.JRE;

import java.math.BigInteger;

import static com.privacylogistics.FF3Cipher.reverseString;
import static com.privacylogistics.FF3Cipher.encode_int_r;
import static com.privacylogistics.FF3Cipher.decode_int;
import static com.privacylogistics.FF3Cipher.hexStringToByteArray;

public class FF3CipherTest {

/*
Expand Down Expand Up @@ -159,7 +155,7 @@ public void testCalculateP() {
String alphabet = "0123456789";
String B = "567890000";
byte[] W = FF3Cipher.hexStringToByteArray("FA330A73");
byte[] P = FF3Cipher.calculateP(i, alphabet, W, B);
byte[] P = FF3Cipher.calculateP(i, alphabet, W, B.toCharArray());
assertArrayEquals(P, new byte[]
{(byte) 250, 51, 10, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, (byte) 129, (byte) 205});
}
Expand All @@ -174,21 +170,21 @@ public void testInvalidPlaintext() throws Exception {

@Test
public void testEncodeBigInt() {
assertEquals("101", reverseString(encode_int_r(BigInteger.valueOf(5), "01", 3)));
assertEquals("11", reverseString(encode_int_r(BigInteger.valueOf(6), "01234", 2)));
assertEquals("00012", reverseString(encode_int_r(BigInteger.valueOf(7), "01234", 5)));
assertEquals("a", reverseString(encode_int_r(BigInteger.valueOf(10), "0123456789abcdef", 1)));
assertEquals("20", reverseString(encode_int_r(BigInteger.valueOf(32), "0123456789abcdef", 2)));
assertEquals("101", reverseString(new String(encode_int_r(BigInteger.valueOf(5), "01", 3))));
assertEquals("11", reverseString(new String(encode_int_r(BigInteger.valueOf(6), "01234", 2))));
assertEquals("00012", reverseString(new String(encode_int_r(BigInteger.valueOf(7), "01234", 5))));
assertEquals("a", reverseString(new String(encode_int_r(BigInteger.valueOf(10), "0123456789abcdef", 1))));
assertEquals("20", reverseString(new String(encode_int_r(BigInteger.valueOf(32), "0123456789abcdef", 2))));
}

@Test
public void testDecodeInt() {
assertEquals(BigInteger.valueOf(321), (decode_int("321", "0123456789")));
assertEquals(BigInteger.valueOf(101), (decode_int("101", "0123456789")));
assertEquals(BigInteger.valueOf(101), (decode_int("00101", "0123456789")));
assertEquals(BigInteger.valueOf(0x02), (decode_int("02", "0123456789abcdef")));
assertEquals(BigInteger.valueOf(0xAA), (decode_int("aa", "0123456789abcdef")));
assertEquals(new BigInteger("2658354847544284194395037922"), (decode_int("2658354847544284194395037922", "0123456789")));
assertEquals(BigInteger.valueOf(321), (decode_int_r("123".toCharArray(), "0123456789")));
assertEquals(BigInteger.valueOf(101), (decode_int_r("101".toCharArray(), "0123456789")));
assertEquals(BigInteger.valueOf(101), (decode_int_r("10100".toCharArray(), "0123456789")));
assertEquals(BigInteger.valueOf(0x02), (decode_int_r("20".toCharArray(), "0123456789abcdef")));
assertEquals(BigInteger.valueOf(0xAA), (decode_int_r("aa".toCharArray(), "0123456789abcdef")));
assertEquals(new BigInteger("2297305934914824457484538562"), (decode_int_r("2658354847544284194395037922".toCharArray(), "0123456789")));
}

@Test
Expand Down

0 comments on commit dd5d3ac

Please sign in to comment.