Skip to content

Refactor the interface ICryptaNode #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/CryptatorTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ jobs :
steps:
- name: Checkhout the repository
uses: actions/checkout@v3
- name: Set up JDK 17
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '11'
distribution: 'adopt'
cache: 'maven'
- name: Test with Maven
run: mvn -B test -Dtest=ExtensiveTesting --file pom.xml
run: mvn -B test -Dtest=ExtensiveTesting --file pom.xml
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyy</maven.build.timestamp.format>
<!-- Java source/target to use for compilation. -->
<javac.target>17</javac.target>
<javac.source>17</javac.source>
<javac.target>11</javac.target>
<javac.source>11</javac.source>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/args4j/args4j -->
Expand Down Expand Up @@ -126,11 +126,11 @@
<!-- Only required when JAVA_HOME isn't at least Java 9 and when haven't
configured the maven-toolchains-plugin -->
<jdkToolchain>
<version>17</version>
<version>11</version>
</jdkToolchain>
<release>17</release>
<source>16</source>
<target>16</target>
<release>11</release>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private IntVar[] getGCCOccs(int lb, int ub) {

@Override
public void accept(ICryptaNode node, int numNode) {
if (node.isWordLeaf()) {
if (node.isWord()) {
final char[] w = node.getWord();
if (w.length > 0) firstSymbols.add(node.getWord()[0]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cryptator/solver/AdaptiveSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public final int getMaxLength() {

@Override
public void accept(ICryptaNode node, int numNode) {
if (node.isWordLeaf()) {
if (node.isWord()) {
final int len = node.getWord().length;
if (len > maxLen) maxLen = len;
}
Expand Down
87 changes: 52 additions & 35 deletions src/main/java/cryptator/solver/CryptaBignumModeler.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@
*/
package cryptator.solver;

import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.expression.discrete.arithmetic.ArExpression;
import org.chocosolver.solver.variables.IntVar;

import cryptator.CryptaOperator;
import cryptator.config.CryptaConfig;
import cryptator.specs.ICryptaModeler;
import cryptator.specs.ICryptaNode;
import cryptator.tree.CryptaConstant;
import cryptator.tree.CryptaOperatorDetection;
import cryptator.tree.TreeTraversals;
import cryptator.tree.TreeUtils;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.expression.discrete.arithmetic.ArExpression;
import org.chocosolver.solver.variables.IntVar;

import java.util.ArrayDeque;
import java.util.Deque;

public class CryptaBignumModeler implements ICryptaModeler {

Expand Down Expand Up @@ -60,14 +63,17 @@ private ArExpression[] makeWordVars(char[] word) {
return vars;
}

private ArExpression[] makeConstantVars(CryptaConstant constant) {
var ints =constant.changeBaseLittleEndian(config.getArithmeticBase());
final int n = ints.length;
ArExpression[] vars = new ArExpression[n];
for (int i = 0; i < n; i++) {
vars[i] = model.intVar(ints[i]);
}
return vars;
private ArExpression[] makeConstVars(char[] word) {
List<ArExpression> vars = new ArrayList<>();
BigInteger n = new BigInteger(new String(word));
BigInteger b = BigInteger.valueOf(config.getArithmeticBase());
while (n.compareTo(BigInteger.ZERO) > 0) {
BigInteger[] r = n.divideAndRemainder(b);
n = r[0];
vars.add(model.intVar(r[1].intValueExact()));
}
ArExpression[] res = new ArExpression[vars.size()];
return vars.toArray(res);
}


Expand Down Expand Up @@ -98,29 +104,40 @@ private void applyEQ(ArExpression[] a, ArExpression[] b) {
a1.carries[n - 1].eq(b1.carries[n - 1]).decompose().post();
}

private void apply(CryptaOperator op, ArExpression[] a, ArExpression[] b) {
switch (op) {
case ADD: {
stack.push(applyADD(a, b));
break;
}
case EQ: {
applyEQ(a, b);
if (!stack.isEmpty()) // TODO Raise CryptaModelException instead !
throw new IllegalStateException("Stack is not empty after accepting a relational operator.");
else break;
}
default :
// Should never be in the default case, this exception is
// a program break in order to recall to modify the switch if
// a new operator in BigNum is added.
// Example case : we remove the MUL operator in computeUnsupportedBignumOperator
throw new IllegalStateException("Bignum operator is not yet implemented");
}
}
@Override
public void accept(ICryptaNode node, int numNode) {
super.accept(node, numNode);
if (node.isConstantLeaf()){
stack.push(makeConstantVars((CryptaConstant) node));
} else if (node.isWordLeaf()){
stack.push(makeWordVars(node.getWord()));
} else if (!node.getOperator().equals(CryptaOperator.AND)) {
final ArExpression[] b = stack.pop();
final ArExpression[] a = stack.pop();
switch (node.getOperator()) {
case ADD -> stack.push(applyADD(a, b));
case EQ -> {
applyEQ(a, b);
if (!stack.isEmpty())
throw new IllegalStateException("Stack is not empty after accepting a relational operator.");
}
default ->
// Should never be in the default case, this exception is
// a program break in order to recall to modify the switch if
// a new operator in BigNum is added.
// Example case : we remove the MUL operator in computeUnsupportedBignumOperator
throw new IllegalStateException("Bignum operator is not yet implemented");
if(node.isInternalNode()) {
if(! node.getOperator().equals(CryptaOperator.AND)) {
final ArExpression[] b = stack.pop();
final ArExpression[] a = stack.pop();
apply(node.getOperator(), a, b);
} // else do nothing ; constraint are posted when the relational operator is popped.
} else {
if (node.isConstant()){
stack.push(makeConstVars(node.getWord()));
} else {
stack.push(makeWordVars(node.getWord()));
}
}
}
Expand Down
46 changes: 26 additions & 20 deletions src/main/java/cryptator/solver/CryptaModeler.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
*/
package cryptator.solver;

import cryptator.config.CryptaConfig;
import cryptator.specs.ICryptaModeler;
import cryptator.specs.ICryptaNode;
import cryptator.tree.CryptaConstant;
import cryptator.tree.TreeTraversals;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.function.Function;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.expression.discrete.arithmetic.ArExpression;
import org.chocosolver.solver.expression.discrete.relational.ReExpression;
import org.chocosolver.solver.variables.IntVar;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.function.Function;
import cryptator.config.CryptaConfig;
import cryptator.specs.ICryptaModeler;
import cryptator.specs.ICryptaNode;
import cryptator.tree.TreeTraversals;

public class CryptaModeler implements ICryptaModeler {

Expand All @@ -46,22 +46,28 @@ public ModelerConsumer(Model model, CryptaConfig config) {
wordVarBuilder = config.getHornerScheme() ? new HornerVarBuilder() : new ExponentiationVarBuilder();
}

private IntVar makeWordVar(char[] word) {
return wordVarBuilder.apply(word);
private IntVar makeWordVar(ICryptaNode node) {
return wordVarBuilder.apply(node.getWord());
}

private IntVar makeWordConst(ICryptaNode node) {
return model.intVar(Integer.parseInt(new String(node.getWord())));
}

@Override
public void accept(ICryptaNode node, int numNode) {
super.accept(node, numNode);
if (node.isConstantLeaf()) {
stack.push(model.intVar(((CryptaConstant) node).getConstant()));
} else if (node.isWordLeaf()) {
stack.push(makeWordVar(node.getWord()));
} else {
final ArExpression b = stack.pop();
final ArExpression a = stack.pop();
stack.push(node.getOperator().getExpression().apply(a, b));
}
super.accept(node, numNode);
if(node.isInternalNode()) {
final ArExpression b = stack.pop();
final ArExpression a = stack.pop();
stack.push(node.getOperator().getExpression().apply(a, b));
} else {
if (node.isConstant()) {
stack.push(makeWordConst(node));
} else {
stack.push(makeWordVar(node));
}
}
}

@Override
Expand Down
34 changes: 18 additions & 16 deletions src/main/java/cryptator/specs/ICryptaNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,44 @@ public interface ICryptaNode {
* @return the left child
*/
ICryptaNode getLeftChild();
// FIXME Use java.util.Optional ?

/**
* Gets the right child if any.
*
* @return the right child
*/
ICryptaNode getRightChild();
// FIXME Use java.util.Optional ?

/**
* Checks if the node is a constant leaf of the tree.
* Checks if the node is an internal node of the tree.
*
* @return true, if it is a constant leaf
* @return true, if it is internal node, otherwise it is a leaf
*/
boolean isConstantLeaf();

boolean isInternalNode();


/**
* Checks if the node is a word leaf of the tree.
* Checks if the subtree is a constant of the tree.
*
* @return true, if it is a word leaf
* @return true, if it is constant, otherwise false.
*/
boolean isWordLeaf();
boolean isConstant();

/**
* Checks if the node is an internal node of the tree.
* Checks if the node represents a word, i.e. it is a leaf and not constant.
*
* @return true, if it is internal node
* @return true, if it is a word leaf, otherwise false.
*/
boolean isInternalNode();
default boolean isWord() {
return !isInternalNode() && !isConstant();
}


/**
* Transform parsed node to string.
* For example parse(inOrderPrint(parse("a+'8'=b"))) is the same as parse("a+'8'=b")
* Transform parsed node to string recognized by the grammar.
*
* @return the string representation of the node accepted by the parser
* @return the string representation of the node accepted by the grammar
*/
String write();
String toGrammarString();

}
48 changes: 4 additions & 44 deletions src/main/java/cryptator/tree/CryptaConstant.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,23 @@
*/
package cryptator.tree;

import java.util.ArrayList;
import java.util.List;

public class CryptaConstant extends CryptaLeaf {
public static final int DEFAULT_BASE = 10;
private final int constant;
public CryptaConstant() {
super();
constant = Integer.parseInt(new String(getWord()));
}


public CryptaConstant(String word) {
super(word);
constant = Integer.parseInt(new String(getWord()));
}

public CryptaConstant(char[] word) {
super(word);
constant = Integer.parseInt(new String(getWord()));
}

@Override
public boolean isConstantLeaf() {
public boolean isConstant() {
return true;
}

@Override
public boolean isWordLeaf() {
return false;
}

public int getConstant() {
return constant;
}

/**
* @param newBase : the new base to which convert the current constant (Note the current constant is by default in base 10)
* @return an Integer[] of the little representation of the int in the newBase
*
* For example, the constant 178829 will be res = [13, 8, 10, 11, 2] since
* sum_{i from 0 to newBase - 1} res[i] * newBase^i = 178829
*/
public Integer[] changeBaseLittleEndian(int newBase){
var length = getWord().length;
List<Integer> newInt = new ArrayList<>();
var n = this.constant;
while (n > 0){
var reminder = n % newBase;
var divRes = n / newBase;
newInt.add(reminder);
n = divRes;
}
return newInt.toArray(new Integer[0]);
}

@Override
public String write(){
return "'" + constant + "'";
public String toGrammarString(){
return "'" + new String(getWord()) + "'";
}
}
Loading