├── .gitmodules ├── bin ├── build.sh ├── hidecpu.sh └── shapecpu.sh ├── .travis.yml ├── .gitignore ├── shapecpu ├── samples │ ├── README.md │ ├── .project │ ├── LICENSE.md │ ├── sort.asm │ └── creditcard.asm ├── src │ ├── main │ │ ├── resources │ │ │ └── command-line.txt │ │ └── java │ │ │ └── com │ │ │ └── grack │ │ │ └── shapecpu │ │ │ ├── assembler │ │ │ ├── Value.java │ │ │ ├── Opcode.java │ │ │ ├── Program.java │ │ │ ├── Compiler.java │ │ │ ├── Line.java │ │ │ └── Parser.java │ │ │ ├── Main.java │ │ │ └── CPU.java │ └── test │ │ ├── resources │ │ └── com │ │ │ └── grack │ │ │ └── shapecpu │ │ │ ├── sort_input.txt │ │ │ ├── sort_output.txt │ │ │ ├── creditcard_output.txt │ │ │ └── creditcard_input.txt │ │ └── java │ │ └── com │ │ └── grack │ │ └── shapecpu │ │ ├── SortSampleTest.java │ │ └── CreditCardSampleTest.java ├── pom.xml └── pseudocode.txt ├── hidecpu2 ├── src │ ├── test │ │ ├── resources │ │ │ ├── opcode_swap.asm │ │ │ ├── opcode_add.asm │ │ │ ├── opcode_load_store.asm │ │ │ ├── opcode_branch.asm │ │ │ └── data_indirect.asm │ │ └── java │ │ │ └── com │ │ │ └── grack │ │ │ └── hidecpu2 │ │ │ └── assembler │ │ │ ├── AllTests.java │ │ │ ├── ParserTest.java │ │ │ ├── CompilerTest.java │ │ │ └── RunTest.java │ └── main │ │ ├── java │ │ └── com │ │ │ └── grack │ │ │ └── hidecpu2 │ │ │ ├── assembler │ │ │ ├── OpTarget.java │ │ │ ├── OpSource.java │ │ │ ├── UnaryOpcode.java │ │ │ ├── BranchType.java │ │ │ ├── Opcode.java │ │ │ ├── line │ │ │ │ ├── EmptyLine.java │ │ │ │ ├── SegmentLine.java │ │ │ │ ├── DataLine.java │ │ │ │ ├── BranchLine.java │ │ │ │ ├── UnaryLine.java │ │ │ │ ├── MaskValueLine.java │ │ │ │ ├── LineBuilder.java │ │ │ │ ├── Line.java │ │ │ │ └── StandardLine.java │ │ │ ├── Value.java │ │ │ ├── Program.java │ │ │ ├── Compiler.java │ │ │ └── Parser.java │ │ │ └── Main.java │ │ └── resources │ │ └── command-line.txt ├── samples │ ├── cmp.asm │ ├── mov.asm │ ├── sort.asm │ └── creditcard.asm ├── pom.xml └── opcodes.v2.md ├── LICENSE.md ├── parent ├── .settings │ └── org.eclipse.m2e.core.prefs ├── .project └── pom.xml ├── hidecpu ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── grack │ │ │ │ └── hidecpu │ │ │ │ ├── assembler │ │ │ │ ├── OpTarget.java │ │ │ │ ├── OpSource.java │ │ │ │ ├── BranchType.java │ │ │ │ ├── Opcode.java │ │ │ │ ├── Value.java │ │ │ │ ├── Program.java │ │ │ │ ├── Compiler.java │ │ │ │ ├── Line.java │ │ │ │ └── Parser.java │ │ │ │ └── Main.java │ │ └── resources │ │ │ ├── command-line.txt │ │ │ └── creditcard.asm │ └── test │ │ └── java │ │ └── com │ │ └── grack │ │ └── hidecpu │ │ └── CPUTest.java ├── samples │ ├── cmp.asm │ ├── mov.asm │ ├── creditcard.asm │ └── sort.asm ├── pom.xml └── opcodes.md ├── .github └── dependabot.yml ├── core ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── grack │ │ │ └── homomorphic │ │ │ ├── graph │ │ │ ├── NodeVisitor.java │ │ │ ├── UnconditionalNodeVisitor.java │ │ │ ├── NotNode.java │ │ │ ├── AndNode.java │ │ │ ├── XorNode.java │ │ │ ├── InputNode.java │ │ │ ├── OutputNode.java │ │ │ ├── ConstantNode.java │ │ │ └── Node.java │ │ │ ├── logging │ │ │ ├── LoggingBitNodeType.java │ │ │ ├── LoggingStateFactory.java │ │ │ ├── LoggingState.java │ │ │ ├── LoggingBit.java │ │ │ └── LoggingBitFactory.java │ │ │ ├── fhe │ │ │ ├── FheBit.java │ │ │ ├── FheContext.java │ │ │ ├── FheFactory.java │ │ │ └── FheMath.java │ │ │ ├── ops │ │ │ ├── StateFactory.java │ │ │ ├── BitAndBit.java │ │ │ ├── WordAndBit.java │ │ │ ├── NativeBitFactory.java │ │ │ ├── State.java │ │ │ ├── NativeBit.java │ │ │ └── Bit.java │ │ │ ├── engine │ │ │ └── Engine.java │ │ │ └── light │ │ │ ├── LightBit.java │ │ │ ├── WordArrayDumper.java │ │ │ ├── LightBitFactory.java │ │ │ ├── StandardState.java │ │ │ └── StandardStateFactory.java │ └── test │ │ └── java │ │ └── com │ │ └── grack │ │ └── homomorphic │ │ ├── light │ │ └── LightNativeBitTest.java │ │ ├── fhe │ │ └── FheMathTest.java │ │ ├── BitTest.java │ │ └── graph │ │ └── GraphTest.java └── pom.xml ├── brainstorm.md ├── PRIOR-ART.md └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bin/build.sh: -------------------------------------------------------------------------------- 1 | mvn clean compile package -f parent/pom.xml 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | before_script: 3 | - cd parent 4 | jdk: 5 | - oraclejdk11 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */target 3 | */.settings 4 | */.project 5 | */.classpath 6 | workspace 7 | 8 | -------------------------------------------------------------------------------- /bin/hidecpu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp hidecpu/target/hidecpu-1.0-SNAPSHOT.jar com.grack.hidecpu.Main "$@" 3 | -------------------------------------------------------------------------------- /shapecpu/samples/README.md: -------------------------------------------------------------------------------- 1 | Samples provided by ShapeCPU Java implementation (https://hcrypt.com/shape-cpu/) 2 | -------------------------------------------------------------------------------- /bin/shapecpu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp shapecpu/target/shapecpu-1.0-SNAPSHOT.jar com.grack.shapecpu.Main "$@" 3 | -------------------------------------------------------------------------------- /hidecpu2/src/test/resources/opcode_swap.asm: -------------------------------------------------------------------------------- 1 | # swap 2 | mov r0, 99 3 | swap [s1], r0 4 | halt 5 | 6 | .data 7 | s1: 8 | data 1 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | This software is licensed under Apache License, version 2.0 ([link](http://www.apache.org/licenses/LICENSE-2.0.html)). 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /parent/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/OpTarget.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | public enum OpTarget { 4 | R0, R1, R2, R3 5 | } 6 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/OpTarget.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | public enum OpTarget { 4 | R0, R1, R2, R3 5 | } 6 | -------------------------------------------------------------------------------- /hidecpu2/src/test/resources/opcode_add.asm: -------------------------------------------------------------------------------- 1 | # add 2 | clrc 3 | add r0, 50 4 | setc 5 | add r0, 48 6 | mov [a1], r0 7 | halt 8 | 9 | .data 10 | a1: 11 | data 0 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/parent" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/NodeVisitor.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public interface NodeVisitor { 4 | boolean visit(Node node); 5 | } 6 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/logging/LoggingBitNodeType.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.logging; 2 | 3 | public enum LoggingBitNodeType { 4 | INPUT, XOR, AND, NOT, OUTPUT 5 | } -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/UnconditionalNodeVisitor.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public interface UnconditionalNodeVisitor { 4 | void visit(Node node); 5 | } 6 | -------------------------------------------------------------------------------- /hidecpu/samples/cmp.asm: -------------------------------------------------------------------------------- 1 | mov r0, 0 2 | cmp r0, 0 3 | beq correct 4 | mov r0, 99 5 | mov [res], r0 6 | halt 7 | 8 | correct: 9 | mov r0, 1 10 | mov [res], r0 11 | halt 12 | 13 | res: 14 | data 0 -------------------------------------------------------------------------------- /hidecpu2/samples/cmp.asm: -------------------------------------------------------------------------------- 1 | mov r0, 0 2 | cmp r0, 0 3 | beq correct 4 | mov r0, 99 5 | mov [res], r0 6 | halt 7 | 8 | correct: 9 | mov r0, 1 10 | mov [res], r0 11 | halt 12 | 13 | res: 14 | data 0 -------------------------------------------------------------------------------- /hidecpu2/src/test/resources/opcode_load_store.asm: -------------------------------------------------------------------------------- 1 | # load/store 2 | mov r0, [m2] 3 | mov [m1], r0 4 | mov r0, 2 5 | mov [m2], r0 6 | halt 7 | 8 | .data 9 | m1: 10 | data 1 11 | m2: 12 | data 99 13 | 14 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/OpSource.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | public enum OpSource { 4 | CONSTANT, 5 | CONSTANT_LOAD, 6 | R0_RELATIVE_LOAD, 7 | R1_RELATIVE_LOAD 8 | } 9 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/OpSource.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | public enum OpSource { 4 | CONSTANT, 5 | CONSTANT_LOAD, 6 | R0_RELATIVE_LOAD, 7 | R1_RELATIVE_LOAD 8 | } 9 | -------------------------------------------------------------------------------- /hidecpu2/src/test/resources/opcode_branch.asm: -------------------------------------------------------------------------------- 1 | cmp r0, 1 2 | blt lt 3 | halt 4 | lt: 5 | mov r0, 200 6 | cmp r0, 10 7 | bgt gt 8 | halt 9 | gt: 10 | mov r0, 99 11 | mov [out], r0 12 | 13 | .data 14 | out: 15 | data 0 -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/BranchType.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | public enum BranchType { 4 | LT, 5 | LTE, 6 | EQ, 7 | CA, 8 | 9 | GTE, 10 | GT, 11 | NE, 12 | NC, 13 | } 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/fhe/FheBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.fhe; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class FheBit { 6 | private BigInteger n; 7 | private int noise; 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/fhe/FheContext.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.fhe; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class FheContext { 6 | private BigInteger privateKey; 7 | private BigInteger publicKey; 8 | } 9 | -------------------------------------------------------------------------------- /shapecpu/samples/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | samples 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/UnaryOpcode.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | /** 4 | * Sub-opcodes for {@link Opcode#UNARY}. 5 | */ 6 | public enum UnaryOpcode { 7 | SHL, 8 | SHR, 9 | ROL, 10 | ROLC, 11 | ROR, 12 | RORC, 13 | NEG, 14 | SWAPN 15 | } 16 | -------------------------------------------------------------------------------- /hidecpu/samples/mov.asm: -------------------------------------------------------------------------------- 1 | mov r0, 99 2 | mov [res1], r0 3 | 4 | mov r1, r0 5 | mov [res2], r1 6 | 7 | add r1, r0 8 | mov [res3], r1 9 | 10 | mov r0, res4 11 | mov [r0], r1 12 | 13 | halt 14 | 15 | res1: 16 | data 0 17 | 18 | res2: 19 | data 0 20 | 21 | res3: 22 | data 0 23 | 24 | res4: 25 | data 0 -------------------------------------------------------------------------------- /hidecpu2/samples/mov.asm: -------------------------------------------------------------------------------- 1 | mov r0, 99 2 | mov [res1], r0 3 | 4 | mov r1, r0 5 | mov [res2], r1 6 | 7 | add r1, r0 8 | mov [res3], r1 9 | 10 | mov r0, res4 11 | mov [r0], r1 12 | 13 | halt 14 | 15 | res1: 16 | data 0 17 | 18 | res2: 19 | data 0 20 | 21 | res3: 22 | data 0 23 | 24 | res4: 25 | data 0 -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/BranchType.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | public enum BranchType { 4 | LT, 5 | LTE, 6 | EQ, 7 | CA, 8 | MI, 9 | XT1, 10 | XT2, 11 | XT3, 12 | 13 | GTE, 14 | GT, 15 | NE, 16 | NC, 17 | NM, 18 | NX1, 19 | NX2, 20 | NX3, 21 | } 22 | -------------------------------------------------------------------------------- /hidecpu/src/main/resources/command-line.txt: -------------------------------------------------------------------------------- 1 | Usage: 2 | hidecpu run [--ticks=] [--debug] 3 | hidecpu assemble [-o ] 4 | hidecpu pretty [-o ] [--process-labels] 5 | 6 | Options: 7 | -h --help Show help 8 | --debug Enable debugging where possible 9 | -------------------------------------------------------------------------------- /hidecpu2/src/main/resources/command-line.txt: -------------------------------------------------------------------------------- 1 | Usage: 2 | hidecpu2 run [--ticks=] [--debug] 3 | hidecpu2 assemble [-o ] 4 | hidecpu2 pretty [-o ] [--process-labels] 5 | 6 | Options: 7 | -h --help Show help 8 | --debug Enable debugging where possible 9 | -------------------------------------------------------------------------------- /shapecpu/src/main/resources/command-line.txt: -------------------------------------------------------------------------------- 1 | Usage: 2 | shapecpu run [--ticks=] [--debug] 3 | shapecpu assemble [-o ] 4 | shapecpu pretty [-o ] [--process-labels] 5 | 6 | Options: 7 | -h --help Show help 8 | --debug Enable debugging where possible 9 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/NotNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class NotNode extends Node { 4 | public NotNode() { 5 | } 6 | 7 | public NotNode(Node in1) { 8 | addInput(in1); 9 | } 10 | 11 | @Override 12 | public Node duplicate() { 13 | return new NotNode(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/AndNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class AndNode extends Node { 4 | public AndNode() { 5 | } 6 | 7 | public AndNode(Node in1, Node in2) { 8 | addInput(in1); 9 | addInput(in2); 10 | } 11 | 12 | @Override 13 | public Node duplicate() { 14 | return new AndNode(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/XorNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class XorNode extends Node { 4 | public XorNode() { 5 | } 6 | 7 | public XorNode(Node in1, Node in2) { 8 | addInput(in1); 9 | addInput(in2); 10 | } 11 | 12 | @Override 13 | public Node duplicate() { 14 | return new XorNode(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /hidecpu2/src/test/resources/data_indirect.asm: -------------------------------------------------------------------------------- 1 | mov r0, pointers 2 | mov r2, 4 3 | loop: 4 | mov r1, [r0] 5 | mov r1, [r1] 6 | add r3, r1 7 | add r0, 1 8 | loop r2, loop 9 | sub r3, 1 # 10+20+40+30-1=99 10 | mov [out], r3 11 | halt 12 | 13 | .data 14 | out: data 0 15 | pointers: data p1, p2, p3, p4 16 | p1: data 10 17 | p2: data 20 18 | p4: data 40 19 | p3: data 30 20 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Opcode.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | /** 4 | * Program opcodes. 5 | */ 6 | public enum Opcode { 7 | LOAD, 8 | STORE, 9 | ROR, 10 | ROL, 11 | NOT, 12 | 13 | ADD, 14 | SUB, 15 | XOR, 16 | AND, 17 | OR, 18 | 19 | CMP, 20 | CARRY, 21 | BRA, 22 | LOOP, 23 | JUMP, 24 | 25 | DATA 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/InputNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class InputNode extends Node { 4 | private String name; 5 | 6 | public InputNode(String name) { 7 | this.name = name; 8 | } 9 | 10 | public String name() { 11 | return name; 12 | } 13 | 14 | @Override 15 | public Node duplicate() { 16 | return new InputNode(name); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/Opcode.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | /** 4 | * Program opcodes. 5 | */ 6 | public enum Opcode { 7 | LOAD, 8 | STORE, 9 | SWAP, 10 | 11 | ADD, 12 | SUB, 13 | XOR, 14 | AND, 15 | OR, 16 | 17 | /** 18 | * See {@link UnaryOpcode}. 19 | */ 20 | UNARY, 21 | 22 | CMP, 23 | SETFLAGS, 24 | BRA, 25 | LOOP, 26 | JUMP, 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/StateFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | /** 4 | * Creates the inter-tick {@link State} environment. 5 | */ 6 | public interface StateFactory { 7 | void allocateWordRegister(String name, int width); 8 | 9 | void allocateBitRegister(String name); 10 | 11 | void allocateWordArrayRegister(String name, int width, int size); 12 | 13 | State createState(); 14 | } 15 | -------------------------------------------------------------------------------- /parent/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | oblivious-cpu-parent 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.m2e.core.maven2Builder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.m2e.core.maven2Nature 16 | 17 | 18 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/BitAndBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | /** 4 | * Helper tuple for addition w/carry. 5 | */ 6 | public class BitAndBit { 7 | private Bit bit1; 8 | private Bit bit2; 9 | 10 | public BitAndBit(Bit bit1, Bit bit2) { 11 | this.bit1 = bit1; 12 | this.bit2 = bit2; 13 | } 14 | 15 | public Bit getBit1() { 16 | return bit1; 17 | } 18 | 19 | public Bit getBit2() { 20 | return bit2; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/WordAndBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | /** 4 | * Helper tuple for addition w/carry. 5 | */ 6 | public class WordAndBit { 7 | private Word word; 8 | private Bit bit; 9 | 10 | public WordAndBit(Word word, Bit bit) { 11 | this.word = word; 12 | this.bit = bit; 13 | } 14 | 15 | public Bit getBit() { 16 | return bit; 17 | } 18 | 19 | public Word getWord() { 20 | return word; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/EmptyLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | public class EmptyLine extends Line { 4 | public EmptyLine(String comment, String label) { 5 | super(comment, label, null, null); 6 | } 7 | 8 | @Override 9 | public int[] assemble() { 10 | return null; 11 | } 12 | 13 | @Override 14 | protected String toStringInternal() { 15 | return ""; 16 | } 17 | 18 | @Override 19 | public int size() { 20 | return 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Value.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | public class Value { 4 | private Object value; 5 | 6 | public Value(int i) { 7 | value = i; 8 | } 9 | 10 | public Value(String s) { 11 | value = s; 12 | } 13 | 14 | public Object getValue() { 15 | return value; 16 | } 17 | 18 | public void setValue(Object value) { 19 | this.value = value; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "" + value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/OutputNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class OutputNode extends Node { 4 | private String name; 5 | 6 | public OutputNode(String name, Node from) { 7 | this.name = name; 8 | addInput(from); 9 | } 10 | 11 | public OutputNode(String name) { 12 | this.name = name; 13 | } 14 | 15 | public String name() { 16 | return name; 17 | } 18 | 19 | @Override 20 | public Node duplicate() { 21 | return new OutputNode(name); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Value.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | public class Value { 4 | private Object value; 5 | 6 | public Value(int i) { 7 | value = i; 8 | } 9 | 10 | public Value(String s) { 11 | value = s; 12 | } 13 | 14 | public Object getValue() { 15 | return value; 16 | } 17 | 18 | public void setValue(Object value) { 19 | this.value = value; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "" + value; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/NativeBitFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | public interface NativeBitFactory { 4 | NativeBit encodeNativeBit(int bit); 5 | 6 | default Bit encodeBit(int bit) { 7 | return new Bit(encodeNativeBit(bit)); 8 | } 9 | 10 | default Word encodeWord(long word, int size) { 11 | Bit[] bits = new Bit[size]; 12 | for (int i = 0; i < size; i++) { 13 | bits[i] = encodeBit((int) ((word & (1 << i)) >> i)); 14 | } 15 | 16 | return new Word(bits); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/State.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | /** 4 | * Inter-tick state. 5 | */ 6 | public interface State { 7 | Word getWordRegister(String name); 8 | 9 | Bit getBitRegister(String name); 10 | 11 | Word[] getWordArrayRegister(String name); 12 | 13 | void setBitRegister(String name, Bit value); 14 | 15 | void setWordRegister(String name, Word value); 16 | 17 | void setWordArrayRegister(String name, Word[] value); 18 | 19 | Bit one(); 20 | 21 | Bit zero(); 22 | 23 | Word negativeOne(int width); 24 | 25 | void debug(Object... things); 26 | } 27 | -------------------------------------------------------------------------------- /hidecpu/samples/creditcard.asm: -------------------------------------------------------------------------------- 1 | # double every second digit 2 | mov r0, 15 3 | doubler: 4 | add r2, [data + r0] 5 | sub r0, 1 6 | mov r1, rol [data + r0] 7 | cmp r1, 10 8 | blt no_sub 9 | # if n * 2 >= 10, we sum the sum of the digits instead of n 10 | sub r1, 9 11 | no_sub: 12 | add r2, r1 13 | loop r0, doubler 14 | 15 | mov [sum], r2 16 | 17 | # Now check that the sum % 10 == 0 18 | check: 19 | cmp r2, 10 20 | blt done 21 | sub r2, 10 22 | jump check 23 | 24 | done: 25 | mov [res], r2 26 | halt 27 | 28 | sum: 29 | data 0 30 | res: 31 | data 0 32 | 33 | data: 34 | data 5, 4, 9, 7, 0, 3, 6, 5, 0, 2, 1, 6, 1, 6, 1, 8 35 | -------------------------------------------------------------------------------- /hidecpu/src/main/resources/creditcard.asm: -------------------------------------------------------------------------------- 1 | # double every second digit 2 | mov r0, 15 3 | doubler: 4 | add r2, [data + r0] 5 | sub r0, 1 6 | mov r1, rol [data + r0] 7 | cmp r1, 10 8 | blt no_sub 9 | # if n * 2 >= 10, we sum the sum of the digits instead of n 10 | sub r1, 9 11 | no_sub: 12 | add r2, r1 13 | loop r0, doubler 14 | 15 | mov [sum], r2 16 | 17 | # Now check that the sum % 10 == 0 18 | check: 19 | cmp r2, 10 20 | blt done 21 | sub r2, 10 22 | jump check 23 | 24 | done: 25 | mov [res], r2 26 | halt 27 | 28 | sum: 29 | data 0 30 | res: 31 | data 0 32 | 33 | data: 34 | data 5, 4, 9, 7, 0, 3, 6, 5, 0, 2, 1, 6, 1, 6, 1, 8 35 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Opcode.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | /** 4 | * Program opcodes. 5 | */ 6 | public enum Opcode { 7 | CMP(1), 8 | CMPa(1 + 16), 9 | BMI(2), 10 | La(3 + 16), 11 | J(4), 12 | BEQ(5), 13 | OR(6), 14 | ORa(6 + 16), 15 | AND(7), 16 | ANDa(7 + 16), 17 | XOR(8), 18 | XORa(8 + 16), 19 | SEC(9), 20 | CLC(10), 21 | ADD(11), 22 | ADDa(11 + 16), 23 | ROR(12), 24 | ROL(13), 25 | L(14), 26 | STa(15 + 16); 27 | 28 | private int value; 29 | 30 | private Opcode(int value) { 31 | this.value = value; 32 | } 33 | 34 | public int getValue() { 35 | return value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/engine/Engine.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.engine; 2 | 3 | import com.grack.homomorphic.ops.NativeBitFactory; 4 | import com.grack.homomorphic.ops.State; 5 | import com.grack.homomorphic.ops.StateFactory; 6 | 7 | public interface Engine { 8 | /** 9 | * Initialize the HME inter-tick state. 10 | */ 11 | void initialize(NativeBitFactory factory, StateFactory stateFactory); 12 | 13 | /** 14 | * Tick the engine. Depending on the implementation of the 15 | * {@link NativeBitFactory}, this may be a direct execution or will generate 16 | * a graph of operations. 17 | */ 18 | void tick(State state); 19 | } 20 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/Value.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | public class Value { 4 | private Object value; 5 | 6 | public Value(int i) { 7 | value = i; 8 | } 9 | 10 | public Value(String s) { 11 | value = s; 12 | } 13 | 14 | public Value(OpTarget t) { 15 | value = t; 16 | } 17 | 18 | public Object getValue() { 19 | return value; 20 | } 21 | 22 | public void setValue(Object value) { 23 | this.value = value; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | if (value instanceof OpTarget) 29 | return ((OpTarget) value).name().toLowerCase(); 30 | return "" + value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /shapecpu/samples/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2011 2 | 3 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 5 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 6 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 7 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 8 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 9 | DEALINGS IN THE SOFTWARE. 10 | 11 | SOFTWARE AND SOURCE CODE MAY BE DOWNLOADED AND MODIFIED FOR EDUCATIONAL OR 12 | ACADEMIC USE. PATENT PCT/EP2012/053165 PENDING. 13 | 14 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/NativeBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | /** 4 | * The native homomorphic system. 5 | */ 6 | public interface NativeBit { 7 | /** 8 | * Performs an xor operation with another bit. 9 | */ 10 | NativeBit xor(NativeBit n); 11 | 12 | /** 13 | * Performs an and operation with another bit. 14 | */ 15 | NativeBit and(NativeBit n); 16 | 17 | /** 18 | * Inverts a bit. 19 | */ 20 | NativeBit not(); 21 | 22 | /** 23 | * Returns a one from the same factory that produced this bit. 24 | */ 25 | NativeBit one(); 26 | 27 | /** 28 | * Returns a zero from the same factory that produced this bit. 29 | */ 30 | NativeBit zero(); 31 | } 32 | -------------------------------------------------------------------------------- /brainstorm.md: -------------------------------------------------------------------------------- 1 | ## The Homomorphic "Hard Drive" 2 | 3 | (not completely thought out...) 4 | 5 | We can use an analagy to the physical hard drive using a virtual spinning platter that is connected to the network in a special way. A virtual hard drive controller is mapped to memory with registers like so: 6 | 7 | ``` 8 | | Address | Register | 9 | | 238 | Operation (1=read, 2=write) | 10 | | 239 | HDD linear address high | 11 | | 240-255 | HDD read/write window | 12 | ``` 13 | 14 | The virtual HDD "spins" each cycle, reading/writing a window of 16 bytes if it matches the HDD linear address. 15 | 16 | Alternative idea: DMA to location in memory rather than using a memory window. 17 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/SegmentLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | public class SegmentLine extends Line { 4 | private String segment; 5 | 6 | public SegmentLine(String comment, String segment) { 7 | super(comment, null, null, null); 8 | this.segment = segment; 9 | } 10 | 11 | public String getSegment() { 12 | return segment; 13 | } 14 | 15 | @Override 16 | public int[] assemble() { 17 | throw new IllegalStateException("This isn't valid for SegmentLine"); 18 | } 19 | 20 | @Override 21 | protected String toStringInternal() { 22 | return "." + segment; 23 | } 24 | 25 | @Override 26 | public int size() { 27 | return 0; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /hidecpu2/samples/sort.asm: -------------------------------------------------------------------------------- 1 | # Bubble sort 2 | 3 | # r0: cmp/swap index 4 | # r1: count 5 | # r2: tmp swap space 6 | # r3: swap count 7 | 8 | start: 9 | mov r3, 0 # swap count 10 | mov r0, list # cmp/swap index 11 | mov r1, [len] # count 12 | sub r1, 2 13 | loop: 14 | mov r2, [r0] # r2<-a 15 | cmp r2, [r0+1] # cmp w/b 16 | blte noswap 17 | 18 | swap r2, [r0+1] # b<->r2 19 | swap r2, [r0] # r2<->a 20 | 21 | add r3, 1 22 | 23 | noswap: 24 | add r0, 1 25 | loop r1, loop 26 | 27 | # Can use this instead of cmp/bne since it'll work the same 28 | # way if we don't care about it after 29 | loop r3, start 30 | 31 | done: 32 | mov r1, 99 33 | mov [len], r1 34 | halt 35 | 36 | marker1: 37 | data 99 38 | len: 39 | data 5 40 | marker2: 41 | data 99 42 | list: 43 | data 6, 5, 4, 9, 5 44 | -------------------------------------------------------------------------------- /shapecpu/samples/sort.asm: -------------------------------------------------------------------------------- 1 | INITAC 0 2 | INITPC start 3 | 4 | list L 6 5 | L 5 6 | L 4 7 | L 9 8 | L 5 9 | 10 | len L 5 11 | 12 | idxa L 0 13 | idxb L 1 14 | temp L 0 15 | swap L 0 16 | 17 | start La idxa 18 | STa loada 19 | STa loada2 20 | STa storeb 21 | La idxb 22 | STa cmpb 23 | STa loadb 24 | STa storea 25 | L 0 26 | STa swap 27 | loada La 0 28 | cmpb CMPa 0 29 | BMI noswap 30 | loada2 La 0 31 | STa temp 32 | loadb La 0 33 | storeb STa 0 34 | La temp 35 | storea STa 0 36 | L 1 37 | STa swap 38 | noswap La idxa 39 | CLC 40 | ADD 1 41 | STa idxa 42 | La idxb 43 | CLC 44 | ADD 1 45 | STa idxb 46 | CMPa len 47 | BEQ next 48 | J start 49 | 50 | next La swap 51 | BEQ end 52 | 53 | L 0 54 | STa idxa 55 | L 1 56 | STa idxb 57 | J start 58 | 59 | end J end -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/ConstantNode.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | public class ConstantNode extends InputNode { 4 | private int value; 5 | 6 | public ConstantNode(String name, int value) { 7 | super(name); 8 | this.value = value; 9 | 10 | if (value != 0 && value != 1) { 11 | throw new IllegalArgumentException("Value must be zero or one"); 12 | } 13 | } 14 | 15 | @Override 16 | public Node duplicate() { 17 | return new ConstantNode(name(), value); 18 | } 19 | 20 | public ConstantNode not() { 21 | if (value == 1) { 22 | return new ConstantNode("zero", 0); 23 | } 24 | if (value == 0) { 25 | return new ConstantNode("one", 1); 26 | } 27 | throw new IllegalArgumentException("Value must be zero or one"); 28 | } 29 | 30 | public int value() { 31 | return value; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/DataLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.google.common.base.Joiner; 4 | import com.grack.hidecpu2.assembler.Opcode; 5 | import com.grack.hidecpu2.assembler.Value; 6 | 7 | public class DataLine extends Line { 8 | public DataLine(String comment, String label, Opcode opcode, Value[] data) { 9 | super(comment, label, opcode, data); 10 | } 11 | 12 | @Override 13 | public int[] assemble() { 14 | int[] output = new int[values.length]; 15 | for (int i = 0; i < values.length; i++) 16 | output[i] = (Integer)values[i].getValue(); 17 | return output; 18 | } 19 | 20 | @Override 21 | protected String toStringInternal() { 22 | return "data" + "\t" + Joiner.on(", ").join(values); 23 | } 24 | 25 | @Override 26 | public int size() { 27 | return values.length; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /hidecpu2/samples/creditcard.asm: -------------------------------------------------------------------------------- 1 | mov r0, 15 2 | doubler: 3 | # double every second digit 4 | add r2, [data + r0] 5 | sub r0, 1 6 | mov r1, [data + r0] 7 | shl r1 8 | cmp r1, 10 9 | blt no_sub 10 | # if n * 2 >= 10, we sum the sum of the digits instead of n 11 | sub r1, 9 12 | no_sub: 13 | add r2, r1 14 | loop r0, doubler 15 | 16 | mov [sum], r2 17 | 18 | # Now check that the sum % 10 == 0 19 | check: 20 | # Add 10 to r2 so we can omit the zero case 21 | add r2, 10 22 | 23 | # r2 * 0x99 -> r0:r1 24 | mul r2, 0x99 25 | # r0 = (r2 * 0x199) >> 8 26 | add r0, r2 27 | # If r0 & 0xf == 0xf, this was a multiple of 10 28 | and r0, 0xf 29 | cmp r0, 0xf 30 | bne fail 31 | mov r2, 99 32 | 33 | fail: 34 | mov [res], r2 35 | halt 36 | 37 | 38 | sum: 39 | data 0 40 | res: 41 | data 0 42 | 43 | data: 44 | # 5497 0365 0216 1618 45 | data 5, 4, 9, 7, 0, 3, 6, 5, 0, 2, 1, 6, 1, 6, 1, 8 46 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/BranchLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.BranchType; 4 | import com.grack.hidecpu2.assembler.Opcode; 5 | import com.grack.hidecpu2.assembler.Value; 6 | 7 | public class BranchLine extends Line { 8 | private BranchType branchType; 9 | 10 | public BranchLine(String comment, String label, Opcode opcode, BranchType branchType, Value value) { 11 | super(comment, label, opcode, new Value[] { value }); 12 | this.branchType = branchType; 13 | } 14 | 15 | @Override 16 | public int[] assemble() { 17 | int op = 0; 18 | op |= opcode.ordinal() << 4; 19 | int val = 0; 20 | return new int[]{ val, op }; 21 | } 22 | 23 | @Override 24 | protected String toStringInternal() { 25 | return "(branch unhandled)"; 26 | } 27 | 28 | @Override 29 | public int size() { 30 | return 2; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/UnaryLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.OpTarget; 4 | import com.grack.hidecpu2.assembler.Opcode; 5 | import com.grack.hidecpu2.assembler.UnaryOpcode; 6 | 7 | public class UnaryLine extends Line { 8 | private OpTarget target; 9 | private UnaryOpcode subop; 10 | 11 | public UnaryLine(String comment, String label, Opcode opcode, OpTarget target, UnaryOpcode subop) { 12 | super(comment, label, opcode, null); 13 | this.target = target; 14 | this.subop = subop; 15 | } 16 | 17 | @Override 18 | public int[] assemble() { 19 | throw new RuntimeException("Unhandled"); 20 | } 21 | 22 | @Override 23 | protected String toStringInternal() { 24 | return subop.name().toLowerCase() + "\t" + target.name().toLowerCase(); 25 | } 26 | 27 | @Override 28 | public int size() { 29 | return 2; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/MaskValueLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.Opcode; 4 | 5 | public class MaskValueLine extends Line { 6 | private int mask; 7 | private int value; 8 | 9 | public MaskValueLine(String comment, String label, Opcode opcode, int mask, int value) { 10 | super(comment, label, opcode, null); 11 | this.mask = mask; 12 | this.value = value; 13 | } 14 | 15 | @Override 16 | public int[] assemble() { 17 | int op = 0; 18 | op |= opcode.ordinal() << 4; 19 | int val = 0; 20 | return new int[]{ val, op }; 21 | } 22 | 23 | @Override 24 | protected String toStringInternal() { 25 | if (mask == 1) { 26 | if (value == 1) 27 | return "setc"; 28 | return "clrc"; 29 | } 30 | 31 | return "(mask unhandled)"; 32 | } 33 | 34 | @Override 35 | public int size() { 36 | return 2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /hidecpu2/src/test/java/com/grack/hidecpu2/assembler/AllTests.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.junit.experimental.theories.ParameterSignature; 7 | import org.junit.experimental.theories.ParameterSupplier; 8 | import org.junit.experimental.theories.PotentialAssignment; 9 | 10 | public class AllTests extends ParameterSupplier { 11 | @Override 12 | public List getValueSources(ParameterSignature sig) { 13 | List list = new ArrayList<>(); 14 | list.add(PotentialAssignment.forValue("name", "data_indirect.asm")); 15 | list.add(PotentialAssignment.forValue("name", "opcode_add.asm")); 16 | list.add(PotentialAssignment.forValue("name", "opcode_branch.asm")); 17 | list.add(PotentialAssignment.forValue("name", "opcode_load_store.asm")); 18 | list.add(PotentialAssignment.forValue("name", "opcode_swap.asm")); 19 | return list; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /hidecpu2/src/test/java/com/grack/hidecpu2/assembler/ParserTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.io.IOException; 4 | 5 | import org.junit.experimental.theories.ParametersSuppliedBy; 6 | import org.junit.experimental.theories.Theories; 7 | import org.junit.experimental.theories.Theory; 8 | import org.junit.runner.RunWith; 9 | 10 | import com.google.common.base.Charsets; 11 | import com.google.common.io.CharSource; 12 | import com.google.common.io.Resources; 13 | 14 | @RunWith(Theories.class) 15 | public class ParserTest { 16 | /** 17 | * Attempt to parse all the samples. 18 | */ 19 | @Theory 20 | public void parseFile(@ParametersSuppliedBy(AllTests.class) String file) throws IOException { 21 | CharSource src = Resources.asCharSource(getClass().getResource("/" + file), Charsets.UTF_8); 22 | Parser parser = new Parser(src); 23 | Program program = parser.parse(); 24 | // System.out.println(file); 25 | // System.out.println(program); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /parent/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.grack.obliviouscpu 7 | parent 8 | pom 9 | 1.0-SNAPSHOT 10 | Oblivious CPU Parent 11 | 12 | 13 | ../core 14 | ../shapecpu 15 | ../hidecpu 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | maven-surefire-plugin 24 | 25 | ${env.JAVA_HOME}/bin/java 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Program.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.google.common.primitives.Ints; 7 | 8 | public class Program { 9 | private Value initAc; 10 | private Value initPc; 11 | 12 | private List lines = new ArrayList<>(); 13 | 14 | public Value getInitAc() { 15 | return initAc; 16 | } 17 | 18 | public void setInitAc(Value initAc) { 19 | this.initAc = initAc; 20 | } 21 | 22 | public Value getInitPc() { 23 | return initPc; 24 | } 25 | 26 | public void setInitPc(Value initPc) { 27 | this.initPc = initPc; 28 | } 29 | 30 | public List getLines() { 31 | return lines; 32 | } 33 | 34 | public int[] getProgram() { 35 | ArrayList program = new ArrayList(); 36 | for (Line line : lines) { 37 | if (line.getOpcode() != null) 38 | program.add(line.assemble()); 39 | } 40 | 41 | return Ints.toArray(program); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /hidecpu/samples/sort.asm: -------------------------------------------------------------------------------- 1 | # Bubble sort 2 | 3 | # TODO: this could avoid spilling r1 to memory if we traversed 4 | # the array backwards instead 5 | 6 | start: 7 | mov r3, 0 # swap count 8 | mov r0, list # cmp/swap index 9 | mov r1, [len] # count 10 | sub r1, 2 11 | loop: 12 | # Ditch the current count into memory for now since we need the register 13 | mov [counttmp], r1 14 | 15 | mov r1, [r0] # r1<-a 16 | cmp r1, [r0+1] # cmp w/b 17 | blte noswap 18 | 19 | mov r2, [r0+1] # r2<-b 20 | mov [r0], r2 # a<-b 21 | mov [r0+1], r1 # b<-a 22 | 23 | add r3, 1 24 | 25 | noswap: 26 | mov r1, [counttmp] 27 | add r0, 1 28 | loop r1, loop 29 | 30 | # Can use this instead of cmp/bne since it'll work the same 31 | # way if we don't care about it after 32 | loop r3, start 33 | 34 | done: 35 | mov r1, 99 36 | mov [len], r1 37 | halt 38 | 39 | counttmp: 40 | data 0 41 | 42 | marker1: 43 | data 99 44 | len: 45 | data 5 46 | marker2: 47 | data 99 48 | list: 49 | data 6, 5, 4, 9, 5 50 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Program.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.google.common.primitives.Ints; 7 | 8 | public class Program { 9 | private List lines = new ArrayList<>(); 10 | 11 | public List getLines() { 12 | return lines; 13 | } 14 | 15 | public int[] getProgram() { 16 | ArrayList program = new ArrayList(); 17 | for (Line line : lines) { 18 | if (line.getOpcode() != null) 19 | for (int i : line.assemble()) 20 | program.add(i); 21 | } 22 | 23 | return Ints.toArray(program); 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | StringBuilder builder = new StringBuilder(); 29 | int lineNumber = 0; 30 | for (Line line : lines) { 31 | if (line.getOpcode() == null) 32 | builder.append(line); 33 | else 34 | builder.append(line.toString(lineNumber++)); 35 | builder.append('\n'); 36 | } 37 | 38 | return builder.toString(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Compiler { 7 | public Compiler() { 8 | } 9 | 10 | public void compile(Program program) { 11 | // Remove all the empty lines 12 | program.getLines().removeIf((line) -> line.isEmpty()); 13 | 14 | Map indexes = new HashMap<>(); 15 | 16 | // Process indexes 17 | int lineNumber = 0; 18 | for (Line line : program.getLines()) { 19 | if (line.getLabel() != null) { 20 | indexes.put(line.getLabel(), lineNumber); 21 | line.setLabel(null); 22 | } 23 | lineNumber++; 24 | } 25 | 26 | updateValue(indexes, program.getInitAc()); 27 | updateValue(indexes, program.getInitPc()); 28 | 29 | program.getLines().forEach( 30 | (line) -> updateValue(indexes, line.getValue())); 31 | } 32 | 33 | private void updateValue(Map indexes, Value value) { 34 | if (value == null) 35 | return; 36 | 37 | if (value.getValue() instanceof String) 38 | value.setValue(indexes.get(value.getValue())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Line.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | public class Line { 4 | private String label; 5 | private Opcode opcode; 6 | private Value value; 7 | 8 | public Line(String label, Opcode opcode, Value value) { 9 | this.label = label; 10 | this.opcode = opcode; 11 | this.value = value; 12 | } 13 | 14 | public String getLabel() { 15 | return label; 16 | } 17 | 18 | public void setLabel(String label) { 19 | this.label = label; 20 | } 21 | 22 | public Opcode getOpcode() { 23 | return opcode; 24 | } 25 | 26 | public void setOpcode(Opcode opcode) { 27 | this.opcode = opcode; 28 | } 29 | 30 | public Value getValue() { 31 | return value; 32 | } 33 | 34 | public void setValue(Value value) { 35 | this.value = value; 36 | } 37 | 38 | public boolean isEmpty() { 39 | return label == null && opcode == null; 40 | } 41 | 42 | public int assemble() { 43 | return opcode.getValue() << 8 | (int) (value == null ? 0 : value.getValue()); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | // Empty line 49 | if (isEmpty()) 50 | return ""; 51 | 52 | return (label == null ? "" : label) + "\t" + opcode + "\t" 53 | + (value == null ? "" : value); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/Program.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.google.common.primitives.Ints; 7 | import com.grack.hidecpu2.assembler.line.Line; 8 | import com.grack.hidecpu2.assembler.line.SegmentLine; 9 | 10 | public class Program { 11 | private List lines = new ArrayList<>(); 12 | 13 | public List getLines() { 14 | return lines; 15 | } 16 | 17 | public int[] getProgram(String whichSegment) { 18 | ArrayList program = new ArrayList(); 19 | String segment = "code"; 20 | for (Line line : lines) { 21 | if (line instanceof SegmentLine) { 22 | segment = ((SegmentLine) line).getSegment(); 23 | continue; 24 | } 25 | if (!segment.equals(whichSegment)) { 26 | continue; 27 | } 28 | for (int i : line.assemble()) 29 | program.add(i); 30 | } 31 | 32 | return Ints.toArray(program); 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | StringBuilder builder = new StringBuilder(); 38 | int lineNumber = 0; 39 | for (Line line : lines) { 40 | if (line instanceof SegmentLine) 41 | lineNumber = 0; 42 | builder.append(line.toString(lineNumber)); 43 | lineNumber += line.size(); 44 | builder.append('\n'); 45 | } 46 | 47 | return builder.toString(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/light/LightBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import com.grack.homomorphic.ops.NativeBit; 4 | 5 | /** 6 | * Uses the bit 0 for the actual value of the native bit 7 | */ 8 | public class LightBit implements NativeBit { 9 | private int value; 10 | private LightBitFactory factory; 11 | 12 | public LightBit(LightBitFactory factory, int value) { 13 | this.factory = factory; 14 | this.value = value; 15 | } 16 | 17 | @Override 18 | public NativeBit xor(NativeBit n) { 19 | factory.xor++; 20 | LightBit other = (LightBit)n; 21 | return new LightBit(factory, scramble(value ^ other.value)); 22 | } 23 | 24 | @Override 25 | public NativeBit not() { 26 | return xor(new LightBit(factory, 1)); 27 | } 28 | 29 | @Override 30 | public NativeBit and(NativeBit n) { 31 | factory.and++; 32 | LightBit other = (LightBit)n; 33 | return new LightBit(factory, scramble(value & other.value)); 34 | } 35 | 36 | @Override 37 | public NativeBit one() { 38 | return factory.encodeNativeBit(1); 39 | } 40 | 41 | @Override 42 | public NativeBit zero() { 43 | return factory.encodeNativeBit(0); 44 | } 45 | 46 | private int scramble(int value) { 47 | return factory.scramble(value); 48 | } 49 | 50 | public int value() { 51 | return value; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return Integer.toString(factory.extract(this)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/test/java/com/grack/homomorphic/light/LightNativeBitTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import com.grack.homomorphic.light.LightBitFactory; 9 | import com.grack.homomorphic.ops.Bit; 10 | import com.grack.homomorphic.ops.Word; 11 | 12 | public class LightNativeBitTest { 13 | private LightBitFactory factory; 14 | private Bit one; 15 | private Bit zero; 16 | 17 | @Before 18 | public void setup() { 19 | factory = new LightBitFactory(); 20 | one = factory.encodeBit(1); 21 | zero = factory.encodeBit(0); 22 | } 23 | 24 | @Test 25 | public void bitValuesAreExtractable() { 26 | assertEquals(1, factory.extract(one)); 27 | assertEquals(0, factory.extract(zero)); 28 | } 29 | 30 | @Test 31 | public void wordsHaveCorrectBitValues() { 32 | Word word = factory.encodeWord(0b10001111, 8); 33 | assertEquals(1, factory.extract(word.bit(0))); 34 | assertEquals(1, factory.extract(word.bit(1))); 35 | assertEquals(1, factory.extract(word.bit(2))); 36 | assertEquals(1, factory.extract(word.bit(3))); 37 | assertEquals(0, factory.extract(word.bit(4))); 38 | assertEquals(0, factory.extract(word.bit(5))); 39 | assertEquals(0, factory.extract(word.bit(6))); 40 | assertEquals(1, factory.extract(word.bit(7))); 41 | } 42 | 43 | @Test 44 | public void wordsAreExtractable() { 45 | assertEquals(0b10001111, factory.extract(factory.encodeWord(0b10001111, 8))); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/logging/LoggingStateFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.logging; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.grack.homomorphic.ops.Bit; 7 | import com.grack.homomorphic.ops.State; 8 | import com.grack.homomorphic.ops.StateFactory; 9 | import com.grack.homomorphic.ops.Word; 10 | 11 | public class LoggingStateFactory implements StateFactory { 12 | private LoggingBitFactory bitFactory; 13 | private static final Map bits = new HashMap<>(); 14 | private static final Map words = new HashMap<>(); 15 | private static final Map wordArrays = new HashMap<>(); 16 | 17 | public LoggingStateFactory(LoggingBitFactory bitFactory) { 18 | this.bitFactory = bitFactory; 19 | } 20 | 21 | @Override 22 | public void allocateWordRegister(String name, int width) { 23 | Word word = bitFactory.createNamedInputWord(name, width); 24 | words.put(name, word); 25 | } 26 | 27 | @Override 28 | public void allocateBitRegister(String name) { 29 | Bit bit = bitFactory.createNamedInputBit(name); 30 | bits.put(name, bit); 31 | } 32 | 33 | @Override 34 | public void allocateWordArrayRegister(String name, int width, int size) { 35 | Word[] words = bitFactory.createNamedInputWordArray(name, width, size); 36 | wordArrays.put(name, words); 37 | } 38 | 39 | @Override 40 | public State createState() { 41 | return new LoggingState(bitFactory, 42 | bitFactory.createNamedInputBit("one"), 43 | bitFactory.createNamedInputBit("zero"), bits, words, wordArrays); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/light/WordArrayDumper.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import com.grack.homomorphic.ops.Word; 4 | 5 | public class WordArrayDumper { 6 | private static final int RUN_LENGTH = 5; 7 | private static final String DUMP = "%08x: %s %s"; 8 | 9 | public static void dump(LightBitFactory factory, Word[] memory) { 10 | long last = -1; 11 | int run = 0; 12 | int size = memory[0].size(); 13 | 14 | int addr; 15 | for (addr = 0; addr < memory.length; addr++) { 16 | long val = factory.extract(memory[addr]); 17 | if (val == last) { 18 | run++; 19 | } else { 20 | if (run > RUN_LENGTH) { 21 | System.err.println(" *"); 22 | } else { 23 | while (run > 0) { 24 | dumpLine(addr - run, factory, size, last); 25 | run--; 26 | } 27 | } 28 | run = 0; 29 | last = val; 30 | dumpLine(addr, factory, size, val); 31 | } 32 | } 33 | 34 | if (run > RUN_LENGTH) { 35 | System.err.println(" *"); 36 | dumpLine(addr - 1, factory, size, last); 37 | System.err.println(String.format(DUMP, addr - 1, 38 | factory.encodeWord(last, size), last, last)); 39 | } else { 40 | // Dump any remaining items that didn't make it into a run 41 | while (run > 0) { 42 | dumpLine(addr - run, factory, size, last); 43 | run--; 44 | } 45 | } 46 | } 47 | 48 | private static void dumpLine(int addr, LightBitFactory factory, int size, 49 | long value) { 50 | System.err.println(String.format(DUMP, addr, 51 | factory.encodeWord(value, size), value & 0xff)); 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/light/LightBitFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import java.util.Random; 4 | 5 | import com.grack.homomorphic.ops.Bit; 6 | import com.grack.homomorphic.ops.NativeBit; 7 | import com.grack.homomorphic.ops.NativeBitFactory; 8 | import com.grack.homomorphic.ops.Word; 9 | 10 | /** 11 | * Implementation of homomorphic CPU, where the bits are encoded as the smallest 12 | * bit in a byte. No privacy is implemented, but this ensure that there is at 13 | * least some scrambling of the contents. 14 | */ 15 | public class LightBitFactory implements NativeBitFactory { 16 | private final Random r = new Random(); 17 | int xor, and; 18 | 19 | @Override 20 | public NativeBit encodeNativeBit(int bit) { 21 | if (bit != 0 && bit != 1) 22 | throw new IllegalArgumentException("bit must be zero or one (not " 23 | + bit + ")"); 24 | 25 | int v = 0; 26 | if (bit == 1) 27 | v = v | 1; 28 | return new LightBit(this, scramble(v)); 29 | } 30 | 31 | public int extract(Bit bit) { 32 | LightBit nativeBit = (LightBit) bit.nativeBit(); 33 | return extract(nativeBit); 34 | } 35 | 36 | public int extract(LightBit nativeBit) { 37 | return nativeBit.value() & 1; 38 | } 39 | 40 | public long extract(Word word) { 41 | long value = 0; 42 | 43 | for (int i = 0; i < word.size(); i++) { 44 | value |= ((long) extract(word.bit(i))) << i; 45 | } 46 | 47 | return value; 48 | } 49 | 50 | public int scramble(int value) { 51 | return (value + (r.nextInt(256) & ~1)) % 256 | 0xf000; 52 | } 53 | 54 | public int getAndCount() { 55 | return and; 56 | } 57 | 58 | public int getXorCount() { 59 | return xor; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/fhe/FheFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.fhe; 2 | 3 | import java.math.BigInteger; 4 | import java.security.SecureRandom; 5 | import java.util.Random; 6 | 7 | import org.jscience.mathematics.function.Polynomial; 8 | import org.jscience.mathematics.function.Term; 9 | import org.jscience.mathematics.function.Variable; 10 | import org.jscience.mathematics.number.LargeInteger; 11 | 12 | public class FheFactory { 13 | private static final int N_BITS = 384; 14 | private static final int N = 8; 15 | 16 | public void generate() { 17 | Random r = new SecureRandom(); 18 | 19 | Variable.Local x = new Variable.Local<>("x"); 20 | 21 | // fn = x^N + 1 22 | Polynomial oneX = Polynomial.valueOf(LargeInteger.ONE, x); 23 | Polynomial fn = oneX.pow(N).plus(LargeInteger.ONE); 24 | 25 | // Generate a random polynomial for which the resultant of it an x^N+1 26 | // is prime 27 | LargeInteger res; 28 | Polynomial p; 29 | 30 | int test = 0; 31 | do { 32 | p = Polynomial.valueOf(LargeInteger.ONE, Term.ONE); 33 | for (int i = 0; i < N; i++) { 34 | BigInteger coef = new BigInteger(N_BITS, r); 35 | coef = coef.subtract(BigInteger.ONE.shiftLeft(N_BITS - 1)) 36 | .shiftLeft(1); 37 | if (i == 0) 38 | p = p.plus(LargeInteger.valueOf(coef)); 39 | else 40 | p = p.plus(oneX.pow(i).times(LargeInteger.valueOf(coef))); 41 | } 42 | res = FheMath.resultant(fn, p, x); 43 | test++; 44 | } while (!new BigInteger(res.toString()).isProbablePrime(10)); 45 | 46 | System.out.println("Tests: " + test); 47 | 48 | } 49 | 50 | public static void main(String[] args) { 51 | new FheFactory().generate(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | public class Compiler { 8 | public Compiler() { 9 | } 10 | 11 | public void compile(Program program) { 12 | List lines = program.getLines(); 13 | 14 | // Remove all the empty lines 15 | lines.removeIf((line) -> line.isEmpty()); 16 | 17 | // Move labels to a real line (assuming no label on the next line) 18 | for (int i = 0; i < lines.size(); i++) { 19 | Line line = lines.get(i); 20 | String label = line.getLabel(); 21 | if (label != null && line.getOpcode() == null 22 | && lines.get(i + 1).getLabel() == null) { 23 | lines.remove(i); 24 | lines.get(i).setLabel(label); 25 | i--; 26 | } 27 | } 28 | 29 | Map indexes = new HashMap<>(); 30 | 31 | // Process indexes 32 | int lineNumber = 0; 33 | for (Line line : lines) { 34 | if (line.getLabel() != null) { 35 | indexes.put(line.getLabel(), lineNumber); 36 | line.setLabel(null); 37 | } 38 | lineNumber += line.size(); 39 | } 40 | 41 | lineNumber = 0; 42 | for (int i = 0; i < lines.size(); i++) { 43 | indexes.put("pc", lineNumber); 44 | updateValue(indexes, lines.get(i).getValue()); 45 | lineNumber += lines.get(i).size(); 46 | } 47 | } 48 | 49 | private void updateValue(Map indexes, Value value) { 50 | if (value == null) 51 | return; 52 | 53 | if (value.getValue() instanceof String) { 54 | Integer index = indexes.get(value.getValue()); 55 | if (index == null) 56 | throw new IllegalStateException("Index not found: " 57 | + value.getValue()); 58 | value.setValue(index); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PRIOR-ART.md: -------------------------------------------------------------------------------- 1 | Prior art: 2 | 3 | - Storage inspired by rotating storage: gates and index "swapped" out. For example, 16 bytes might be available at a time. The CPU 4 | would wait for the index to match a given index, then that data could be moved into memory (or a single byte from a given index 5 | might be loaded to a register). 6 | - Grid of FHE-based CPUs. More limited CPUs (ie: 8-bit) could exchange data across inter-cpu busses to create higher-performance larger 7 | computing units. 8 | - Encrypted termination conditions. Clients can execute larger and larger cycle counts while returning the decrypted result (ie: 8, 16, 32, 9 | 64, etc). CPU can continue executing while it waits for the caller to determine halt. 10 | - Encrypted channel with client. The client can continue to send bundles which are inserted into memory and available to program. The 11 | program can also store encrypted values in a given memory location that are streamed to a client at certain intervals. 12 | - Client can submit both the program and initial data to a FHE execution server. It may include information to query from a 13 | given encrypted database and insert into memory. 14 | - Client may include a program, a given number of execution cycles, then a place to store the result in the database after that number 15 | of cycles have completed. 16 | - Optimizing compiler: provide optimal gates for system + cost, compiler can choose fundamental gates to optimize system for 17 | - Automatic pipelining for larger CPUs. Slice the gate graph into equal bits so that we can reduce the input-to-output path length. 18 | - Automatically fetch ahead assuming PC increments 19 | - PC that increments using a gray code system to avoid paying for additions 20 | - CPU that you can configure parametrically - bit size, register count, etc. Automatically optimize for that setup. 21 | -------------------------------------------------------------------------------- /hidecpu2/src/test/java/com/grack/hidecpu2/assembler/CompilerTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | 6 | import org.junit.experimental.theories.ParametersSuppliedBy; 7 | import org.junit.experimental.theories.Theories; 8 | import org.junit.experimental.theories.Theory; 9 | import org.junit.runner.RunWith; 10 | 11 | import com.google.common.base.Charsets; 12 | import com.google.common.io.CharSource; 13 | import com.google.common.io.Resources; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | @RunWith(Theories.class) 18 | public class CompilerTest { 19 | /** 20 | * Attempt to compile all the samples. 21 | */ 22 | @Theory 23 | public void compileFile(@ParametersSuppliedBy(AllTests.class) String file) throws IOException { 24 | CharSource src = Resources.asCharSource(getClass().getResource("/" + file), Charsets.UTF_8); 25 | Parser parser = new Parser(src); 26 | Program program = parser.parse(); 27 | Compiler compiler = new Compiler(); 28 | compiler.compile(program); 29 | } 30 | 31 | /** 32 | * Attempt to assemble all the samples. 33 | */ 34 | @Theory 35 | public void assembleFile(@ParametersSuppliedBy(AllTests.class) String file) throws IOException { 36 | CharSource src = Resources.asCharSource(getClass().getResource("/" + file), Charsets.UTF_8); 37 | Parser parser = new Parser(src); 38 | Program program = parser.parse(); 39 | Compiler compiler = new Compiler(); 40 | compiler.compile(program); 41 | int[] code = program.getProgram("code"); 42 | int[] data = program.getProgram("data"); 43 | 44 | assertTrue(code.length > 0); 45 | assertTrue(data.length > 0); 46 | 47 | System.out.println(file); 48 | System.out.println(program); 49 | System.out.println("code: " + Arrays.toString(code)); 50 | System.out.println("data: " + Arrays.toString(data)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/LineBuilder.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.BranchType; 4 | import com.grack.hidecpu2.assembler.OpSource; 5 | import com.grack.hidecpu2.assembler.OpTarget; 6 | import com.grack.hidecpu2.assembler.Opcode; 7 | import com.grack.hidecpu2.assembler.UnaryOpcode; 8 | import com.grack.hidecpu2.assembler.Value; 9 | 10 | public class LineBuilder { 11 | private String label; 12 | private Opcode opcode; 13 | private String comment; 14 | 15 | public LineBuilder() { 16 | } 17 | 18 | public LineBuilder withLabel(String label) { 19 | this.label = label; 20 | return this; 21 | } 22 | 23 | public LineBuilder withOpcode(Opcode opcode) { 24 | this.opcode = opcode; 25 | return this; 26 | } 27 | 28 | public LineBuilder withComment(String comment) { 29 | this.comment = comment; 30 | return this; 31 | } 32 | 33 | public EmptyLine createEmpty() { 34 | return new EmptyLine(comment, label); 35 | } 36 | 37 | public SegmentLine createSegment(String segment) { 38 | if (label != null) 39 | throw new IllegalArgumentException(); 40 | if (opcode != null) 41 | throw new IllegalArgumentException(); 42 | return new SegmentLine(comment, segment); 43 | } 44 | 45 | public DataLine createData(Value[] data) { 46 | return new DataLine(comment, label, opcode, data); 47 | } 48 | 49 | public StandardLine createStandard(OpTarget target, OpSource source, Value value) { 50 | return new StandardLine(comment, label, opcode, target, source, value); 51 | } 52 | 53 | public UnaryLine createUnary(OpTarget target, UnaryOpcode subop) { 54 | return new UnaryLine(comment, label, opcode, target, subop); 55 | } 56 | 57 | public MaskValueLine createMaskValue(int mask, int value) { 58 | return new MaskValueLine(comment, label, opcode, mask, value); 59 | } 60 | 61 | public BranchLine createBranch(BranchType branchType, Value value) { 62 | return new BranchLine(comment, label, opcode, branchType, value); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /shapecpu/samples/creditcard.asm: -------------------------------------------------------------------------------- 1 | INITAC 0 2 | INITPC start 3 | 4 | start La no1 5 | ROR 6 | STa no1 7 | La no3 8 | ROR 9 | STa no3 10 | La no5 11 | ROR 12 | STa no5 13 | La no7 14 | ROR 15 | STa no7 16 | La no9 17 | ROR 18 | STa no9 19 | La no11 20 | ROR 21 | STa no11 22 | La no13 23 | ROR 24 | STa no13 25 | La no15 26 | ROR 27 | STa no15 28 | 29 | chk1 La no1 30 | CMP 10 31 | BMI chk3 32 | add1 CLC 33 | ADD 247 34 | STa no1 35 | 36 | chk3 La no3 37 | CMP 10 38 | BMI chk5 39 | add3 CLC 40 | ADD 247 41 | STa no3 42 | 43 | chk5 La no5 44 | CMP 10 45 | BMI chk7 46 | add5 CLC 47 | ADD 247 48 | STa no5 49 | 50 | chk7 La no7 51 | CMP 10 52 | BMI chk9 53 | add7 CLC 54 | ADD 247 55 | STa no7 56 | 57 | chk9 La no9 58 | CMP 10 59 | BMI chk11 60 | add9 CLC 61 | ADD 247 62 | STa no9 63 | 64 | chk11 La no11 65 | CMP 10 66 | BMI chk13 67 | add11 CLC 68 | ADD 247 69 | STa no11 70 | 71 | chk13 La no13 72 | CMP 10 73 | BMI chk15 74 | add13 CLC 75 | ADD 247 76 | STa no13 77 | 78 | chk15 La no15 79 | CMP 10 80 | BMI add17 81 | add15 CLC 82 | ADD 247 83 | STa no15 84 | 85 | add17 CLC 86 | La no1 87 | ADDa no3 88 | ADDa no5 89 | ADDa no7 90 | ADDa no9 91 | ADDa no11 92 | ADDa no13 93 | ADDa no15 94 | STa temp 95 | CLC 96 | La no2 97 | ADDa no4 98 | ADDa no6 99 | ADDa no8 100 | ADDa no10 101 | ADDa no12 102 | ADDa no14 103 | STa temp2 104 | ADDa temp 105 | STa temp3 106 | STa res 107 | 108 | sub CLC 109 | ADD 246 110 | CMP 10 111 | BMI ready 112 | J sub 113 | 114 | ready STa res 115 | end J end 116 | 117 | temp L 0 118 | temp2 L 0 119 | temp3 L 0 120 | res L 0 121 | 122 | L 99 123 | no1 L 5 124 | no2 L 4 125 | no3 L 9 126 | no4 L 7 127 | no5 L 0 128 | no6 L 3 129 | no7 L 6 130 | no8 L 5 131 | no9 L 0 132 | no10 L 2 133 | no11 L 1 134 | no12 L 6 135 | no13 L 1 136 | no14 L 6 137 | no15 L 0 138 | no16 L 0 -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/Line.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.Opcode; 4 | import com.grack.hidecpu2.assembler.Value; 5 | 6 | public abstract class Line { 7 | protected String label; 8 | protected Opcode opcode; 9 | protected Value[] values; 10 | private String comment; 11 | 12 | public Line(String comment, String label, Opcode opcode, Value[] value) { 13 | this.comment = comment; 14 | this.label = label; 15 | this.opcode = opcode; 16 | this.values = value; 17 | } 18 | 19 | public String getComment() { 20 | return comment; 21 | } 22 | 23 | public void setComment(String comment) { 24 | this.comment = comment; 25 | } 26 | 27 | public String getLabel() { 28 | return label; 29 | } 30 | 31 | public void setLabel(String label) { 32 | this.label = label; 33 | } 34 | 35 | public Opcode getOpcode() { 36 | return opcode; 37 | } 38 | 39 | public void setOpcode(Opcode opcode) { 40 | this.opcode = opcode; 41 | } 42 | 43 | public Value[] getValues() { 44 | return values; 45 | } 46 | 47 | public void setValues(Value[] value) { 48 | this.values = value; 49 | } 50 | 51 | abstract public int[] assemble(); 52 | 53 | @Override 54 | public String toString() { 55 | return toString(-1); 56 | } 57 | 58 | public String toString(int line) { 59 | String s = ""; 60 | if (line != -1) { 61 | if (opcode != null) 62 | s += line; 63 | } 64 | 65 | String str = toStringInternal(); 66 | if (getComment() != null) { 67 | if (!str.isEmpty()) 68 | str += "\t"; 69 | str += "#" + getComment(); 70 | } 71 | 72 | if (label != null) { 73 | if (line != -1 && opcode != null && !str.isEmpty()) { 74 | s += "\t" + label + ":\n" + line + "\t"; 75 | } else { 76 | if (line != -1) 77 | s += "\t"; 78 | s += label + ":"; 79 | } 80 | } else { 81 | if (line != -1) 82 | s += "\t"; 83 | } 84 | 85 | return s + str; 86 | } 87 | 88 | abstract protected String toStringInternal(); 89 | 90 | abstract public int size(); 91 | } 92 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/assembler/Parser.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu.assembler; 2 | 3 | import java.io.IOException; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import com.google.common.base.CharMatcher; 8 | import com.google.common.base.Splitter; 9 | import com.google.common.io.CharSource; 10 | 11 | public class Parser { 12 | private CharSource source; 13 | private Splitter LINE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE) 14 | .trimResults().omitEmptyStrings(); 15 | 16 | public Parser(CharSource source) { 17 | this.source = source; 18 | } 19 | 20 | public Program parse() throws IOException { 21 | Program program = new Program(); 22 | List lines = program.getLines(); 23 | source.readLines().forEach((line) -> { 24 | if (line.toLowerCase().startsWith("initac")) { 25 | Iterator it = LINE_SPLITTER.split(line).iterator(); 26 | it.next(); 27 | program.setInitAc(parseValue(it.next())); 28 | } else if (line.toLowerCase().startsWith("initpc")) { 29 | Iterator it = LINE_SPLITTER.split(line).iterator(); 30 | it.next(); 31 | program.setInitPc(parseValue(it.next())); 32 | } else { 33 | lines.add(parseLine(line)); 34 | } 35 | }); 36 | 37 | return program; 38 | } 39 | 40 | private Line parseLine(String line) { 41 | if (line.trim().isEmpty()) 42 | return new Line(null, null, null); 43 | 44 | Iterator pieces = LINE_SPLITTER.split(line).iterator(); 45 | 46 | String label = null; 47 | if (!Character.isWhitespace(line.charAt(0))) { 48 | label = pieces.next(); 49 | } 50 | 51 | String opcode = pieces.next(); 52 | String value = pieces.hasNext() ? pieces.next() : null; 53 | 54 | return new Line(label, parseOpcode(opcode), parseValue(value)); 55 | } 56 | 57 | private Value parseValue(String value) { 58 | if (value == null) 59 | return null; 60 | 61 | if (value.matches("[0-9]+")) 62 | return new Value(Integer.parseInt(value)); 63 | 64 | return new Value(value); 65 | } 66 | 67 | private Opcode parseOpcode(String opcode) { 68 | return Opcode.valueOf(opcode); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/ops/Bit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.ops; 2 | 3 | import com.google.common.base.Preconditions; 4 | 5 | /** 6 | * One encrypted bit. 7 | */ 8 | public class Bit { 9 | private NativeBit nativeBit; 10 | 11 | public Bit(NativeBit fn) { 12 | Preconditions.checkNotNull(fn); 13 | this.nativeBit = fn; 14 | } 15 | 16 | public Bit and(Bit b) { 17 | Preconditions.checkNotNull(b); 18 | return new Bit(nativeBit.and(b.nativeBit)); 19 | } 20 | 21 | public Word and(Word w) { 22 | Preconditions.checkNotNull(w); 23 | Bit[] bits = new Bit[w.size()]; 24 | for (int i = 0; i < w.size(); i++) 25 | bits[i] = and(w.bit(i)); 26 | 27 | return new Word(bits); 28 | } 29 | 30 | public Bit ifThen(Bit a, Bit b) { 31 | Preconditions.checkNotNull(a); 32 | Preconditions.checkNotNull(b); 33 | return this.and(a).or(this.not().and(b)); 34 | } 35 | 36 | public Word ifThen(Word a, Word b) { 37 | Preconditions.checkNotNull(a); 38 | Preconditions.checkNotNull(b); 39 | return this.and(a).xor(this.not().and(b)); 40 | } 41 | 42 | public Bit not() { 43 | return new Bit(nativeBit.not()); 44 | } 45 | 46 | public Bit or(Bit b) { 47 | Preconditions.checkNotNull(b); 48 | return this.xor(b).xor(this.and(b)); 49 | } 50 | 51 | public Bit xor(Bit b) { 52 | Preconditions.checkNotNull(b); 53 | return new Bit(nativeBit.xor(b.nativeBit)); 54 | } 55 | 56 | public NativeBit nativeBit() { 57 | return nativeBit; 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return nativeBit.toString(); 63 | } 64 | 65 | public BitAndBit halfAdd(Bit b) { 66 | Preconditions.checkNotNull(b); 67 | return new BitAndBit(this.xor(b), this.and(b)); 68 | } 69 | 70 | public BitAndBit fullAdd(Bit b, Bit carry) { 71 | Preconditions.checkNotNull(b); 72 | Preconditions.checkNotNull(carry); 73 | 74 | BitAndBit ha1 = this.halfAdd(b); 75 | BitAndBit ha2 = ha1.getBit1().halfAdd(carry); 76 | 77 | return new BitAndBit(ha2.getBit1(), ha1.getBit2().or(ha2.getBit2())); 78 | } 79 | 80 | public Bit one() { 81 | return new Bit(nativeBit().one()); 82 | } 83 | 84 | public Bit zero() { 85 | return new Bit(nativeBit().one()); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /hidecpu/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | hidecpu 5 | jar 6 | hidecpu 7 | http://maven.apache.org 8 | 9 | 10 | UTF-8 11 | 1.8 12 | 13 | 14 | 15 | com.grack.obliviouscpu 16 | parent 17 | 1.0-SNAPSHOT 18 | ../parent/pom.xml 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 27 | ${java.version} 28 | ${java.version} 29 | 30 | 31 | 32 | org.sonatype.plugins 33 | jarjar-maven-plugin 34 | 35 | 36 | package 37 | 38 | jarjar 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | junit 54 | junit 55 | 4.13.2 56 | test 57 | 58 | 59 | com.google.guava 60 | guava 61 | 23.0 62 | 63 | 64 | com.grack.obliviouscpu 65 | core 66 | 1.0-SNAPSHOT 67 | 68 | 69 | com.offbytwo 70 | docopt 71 | 0.6.0.20150202 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /hidecpu2/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | hidecpu2 5 | jar 6 | hidecpu2 7 | http://maven.apache.org 8 | 9 | 10 | UTF-8 11 | 1.8 12 | 13 | 14 | 15 | com.grack.obliviouscpu 16 | parent 17 | 1.0-SNAPSHOT 18 | ../parent/pom.xml 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 27 | ${java.version} 28 | ${java.version} 29 | 30 | 31 | 32 | org.sonatype.plugins 33 | jarjar-maven-plugin 34 | 35 | 36 | package 37 | 38 | jarjar 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | junit 54 | junit 55 | 4.13.1 56 | test 57 | 58 | 59 | com.google.guava 60 | guava 61 | 17.0 62 | 63 | 64 | com.grack.obliviouscpu 65 | core 66 | 1.0-SNAPSHOT 67 | 68 | 69 | org.docopt 70 | docopt 71 | 0.6.0-SNAPSHOT 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /shapecpu/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | shapecpu 5 | jar 6 | shapecpu 7 | http://maven.apache.org 8 | 9 | 10 | UTF-8 11 | 1.8 12 | 13 | 14 | 15 | com.grack.obliviouscpu 16 | parent 17 | 1.0-SNAPSHOT 18 | ../parent/pom.xml 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 27 | ${java.version} 28 | ${java.version} 29 | 30 | 31 | 32 | org.sonatype.plugins 33 | jarjar-maven-plugin 34 | 35 | 36 | package 37 | 38 | jarjar 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | junit 54 | junit 55 | 4.13.2 56 | test 57 | 58 | 59 | com.google.guava 60 | guava 61 | 23.0 62 | 63 | 64 | com.grack.obliviouscpu 65 | core 66 | 1.0-SNAPSHOT 67 | 68 | 69 | com.offbytwo 70 | docopt 71 | 0.6.0.20150202 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /shapecpu/src/test/resources/com/grack/shapecpu/sort_input.txt: -------------------------------------------------------------------------------- 1 | 02 11 1f 08 12 0a 2e 26 22 3d 2f 05 36 2 | 37 30 09 28 0c 1c 24 30 24 3b 33 27 14 3 | 0e 12 2d 2c 16 2e 0a 08 00 15 07 17 1c 4 | 39 3a 32 1f 28 32 3a 28 32 23 1f 11 26 5 | 29 02 39 2e 32 1a 06 28 38 2b 01 25 20 6 | 2d 3a 05 1c 22 20 1a 18 14 07 21 39 00 7 | 30 3e 0c 04 38 2a 06 36 28 2b 17 3f 3a 8 | 31 1c 00 0c 1a 0c 02 20 34 2f 0b 39 32 9 | 24 24 3e 38 1e 00 2a 1e 36 37 09 07 18 10 | 20 2e 0a 04 02 38 2e 2c 38 21 3d 0b 34 11 | 0c 05 11 0a 00 38 08 2c 25 01 1c 14 15 12 | 24 16 1b 1a 09 18 0c 10 03 15 39 15 03 13 | 2f 3b 25 08 01 2a 26 34 11 0b 3b 05 2d 14 | 08 1f 34 3b 01 1e 18 0e 17 31 33 03 2b 15 | 01 03 05 2e 3a 30 08 0c 3d 3b 2a 18 01 16 | 0d 2e 03 0a 01 34 02 3a 23 25 3d 0b 17 17 | 07 0c 04 3b 21 02 26 2c 21 07 09 29 3f 18 | 1e 22 39 2d 3d 04 16 00 19 21 05 07 21 19 | 3e 20 06 36 06 22 28 14 0a 2b 39 0f 22 20 | 15 32 1e 0b 32 22 3a 08 1f 01 17 1f 2d 21 | 34 0c 3e 32 1e 2e 10 3c 0d 39 0a 18 1b 22 | 1a 34 04 22 1a 38 02 34 25 14 20 0a 1b 23 | 03 2b 0b 3d 39 1e 32 12 2a 35 3e 36 2a 24 | 3a 04 26 20 3e 06 28 2c 2f 37 10 2e 1d 25 | 0c 12 2a 33 00 32 32 18 0d 2f 3f 35 01 26 | 24 1e 0e 06 2c 06 24 12 0b 19 10 2c 23 27 | 2c 22 1e 12 06 14 1e 1a 39 2d 09 15 05 28 | 20 20 28 05 0e 2e 0c 3c 15 15 2a 1e 05 29 | 34 0e 2e 2e 2c 38 1e 0e 01 2f 31 39 03 30 | 0b 1a 30 1e 32 20 06 32 1e 1f 17 07 14 31 | 2b 14 2c 01 1c 1c 12 34 33 01 07 3d 0f 32 | 18 15 29 0e 1e 14 2c 22 0d 39 34 0c 2d 33 | 2a 00 28 22 34 36 14 14 0a 03 3a 2b 16 34 | 2f 30 30 14 06 3a 08 28 29 27 16 39 16 35 | 18 2d 3f 3a 10 16 30 18 3d 15 27 09 07 36 | 07 0f 29 10 22 24 08 00 27 29 3e 08 23 37 | 02 20 12 24 18 22 20 1c 1c 39 2e 33 24 38 | 05 22 1e 02 10 3a 32 02 3b 3f 34 11 2a 39 | 25 05 05 0e 3c 36 0a 1c 11 33 1f 29 09 40 | 27 1e 0d 02 08 02 0a 04 2f 20 2a 08 27 41 | 2e 25 22 37 08 35 06 30 0f 28 13 04 20 42 | 38 11 24 29 3e 0e 0e 12 22 2e 01 06 2a 43 | 35 00 1a 1b 28 1a 38 2e 2b 23 0a 1e 35 44 | 2b 38 14 26 1d 07 3c 22 0d 30 2d 18 0c 45 | 00 24 38 1e 2a 08 1a 3a 34 3b 0f 03 1e 46 | 34 17 19 3c 3a 1e 38 30 3f 2d 11 27 0b 47 | 0b 1e 06 3e 2a 1e 0c 00 0a 17 3f 0b 32 48 | 09 3b 15 24 0c 0c 00 26 33 09 0b 11 1f 49 | 32 17 36 37 1c 1e 32 24 32 20 21 26 22 50 | 07 32 14 26 13 27 2e 3a 36 18 2f 14 22 -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | core 5 | jar 6 | core 7 | http://maven.apache.org 8 | 9 | 10 | UTF-8 11 | 1.8 12 | 13 | 14 | 15 | com.grack.obliviouscpu 16 | parent 17 | 1.0-SNAPSHOT 18 | ../parent/pom.xml 19 | 20 | 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 27 | ${java.version} 28 | ${java.version} 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | junit 37 | junit 38 | 4.13.2 39 | test 40 | 41 | 42 | com.google.guava 43 | guava 44 | 23.0 45 | 46 | 47 | com.offbytwo 48 | docopt 49 | 0.6.0.20150202 50 | 51 | 52 | org.jscience 53 | jscience 54 | 4.3.1 55 | 56 | 57 | org.bouncycastle 58 | bcprov-ext-jdk15on 59 | 1.70 60 | 61 | 62 | org.jscience 63 | jscience 64 | 4.3.1 65 | 66 | 67 | org.bouncycastle 68 | bcprov-ext-jdk15on 69 | 1.70 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/line/StandardLine.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler.line; 2 | 3 | import com.grack.hidecpu2.assembler.OpSource; 4 | import com.grack.hidecpu2.assembler.OpTarget; 5 | import com.grack.hidecpu2.assembler.Opcode; 6 | import com.grack.hidecpu2.assembler.Value; 7 | 8 | public class StandardLine extends Line { 9 | private OpTarget target; 10 | private OpSource source; 11 | 12 | public StandardLine(String comment, String label, Opcode opcode, OpTarget target, OpSource source, Value value) { 13 | super(comment, label, opcode, value == null ? null : new Value[] { value }); 14 | this.target = target; 15 | this.source = source; 16 | } 17 | 18 | @Override 19 | public int[] assemble() { 20 | int op = 0; 21 | op |= opcode.ordinal() << 4; 22 | op |= (target == null) ? 0 : (target.ordinal() << 2); 23 | op |= (source == null) ? 0 : (source.ordinal() << 0); 24 | 25 | int val = 0; 26 | Object value = values[0].getValue(); 27 | if (values != null) { 28 | if (value instanceof OpTarget) 29 | val = 255 - ((OpTarget)value).ordinal(); 30 | else 31 | val = (int)value; 32 | } 33 | 34 | return new int[] { val, op }; 35 | } 36 | 37 | @Override 38 | protected String toStringInternal() { 39 | String src = ""; 40 | if (source != null) { 41 | switch (source) { 42 | case CONSTANT: 43 | src = values[0].toString(); 44 | break; 45 | case CONSTANT_LOAD: 46 | src = '[' + values[0].toString() + ']'; 47 | break; 48 | case R0_RELATIVE_LOAD: 49 | src = "[r0 + " + values[0].toString() + ']'; 50 | break; 51 | case R1_RELATIVE_LOAD: 52 | src = "[r1 + " + values[0].toString() + ']'; 53 | break; 54 | } 55 | } 56 | 57 | String s; 58 | 59 | switch (opcode) { 60 | case LOAD: 61 | s = "mov\t" + target.name().toLowerCase() + ", " + src; 62 | break; 63 | case STORE: 64 | s = "mov\t" + src + ", " + target.name().toLowerCase(); 65 | break; 66 | default: 67 | if (target == null) 68 | s = opcode.name().toLowerCase() + "\t" + src; 69 | else 70 | s = opcode.name().toLowerCase() + "\t" + target.name().toLowerCase() + ", " + src; 71 | } 72 | 73 | return s; 74 | } 75 | 76 | @Override 77 | public int size() { 78 | return 2; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/Compiler.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import com.grack.hidecpu2.assembler.line.EmptyLine; 8 | import com.grack.hidecpu2.assembler.line.Line; 9 | import com.grack.hidecpu2.assembler.line.SegmentLine; 10 | 11 | public class Compiler { 12 | public Compiler() { 13 | } 14 | 15 | public void compile(Program program) { 16 | Map indexes = new HashMap<>(); 17 | List lines = program.getLines(); 18 | 19 | String segment = "code"; 20 | 21 | // Process indexes 22 | int lineNumber = 0; 23 | for (Line line : lines) { 24 | if (line instanceof SegmentLine) { 25 | SegmentLine segmentLine = (SegmentLine) line; 26 | segment = segmentLine.getSegment(); 27 | lineNumber = 0; 28 | continue; 29 | } 30 | 31 | if (line.getLabel() != null) { 32 | indexes.put(line.getLabel(), lineNumber); 33 | line.setLabel(null); 34 | } 35 | lineNumber += line.size(); 36 | } 37 | 38 | // Remove all the empty lines 39 | lines.removeIf((line) -> line instanceof EmptyLine); 40 | 41 | segment = "code"; 42 | 43 | lineNumber = 0; 44 | for (int i = 0; i < lines.size(); i++) { 45 | Line line = lines.get(i); 46 | line.setComment(null); 47 | if (line instanceof SegmentLine) { 48 | SegmentLine segmentLine = (SegmentLine) line; 49 | segment = segmentLine.getSegment(); 50 | lineNumber = 0; 51 | continue; 52 | } 53 | 54 | if (segment.equals("code")) { 55 | indexes.put("pc", lineNumber); 56 | lineNumber += line.size(); 57 | } else { 58 | indexes.remove("pc"); 59 | } 60 | Value[] values = line.getValues(); 61 | if (values != null) { 62 | for (Value value : values) 63 | updateValue(indexes, value); 64 | } 65 | } 66 | } 67 | 68 | private void updateValue(Map indexes, Value value) { 69 | if (value == null) 70 | return; 71 | 72 | Object val = value.getValue(); 73 | if (val instanceof String) { 74 | if (((String)val).matches("r[0-3]")) 75 | return; 76 | 77 | Integer index = indexes.get(val); 78 | if (index == null) 79 | throw new IllegalStateException("Index not found: " 80 | + val); 81 | value.setValue(index); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | oblivious-cpu [![Build Status](https://travis-ci.org/mmastrac/oblivious-cpu.svg?branch=master)](https://travis-ci.org/mmastrac/oblivious-cpu) 2 | ============= 3 | 4 | Two CPUs based on Fully Homomorphic Encryption ([Wikipedia](https://en.wikipedia.org/wiki/Homomorphic_encryption#Fully_homomorphic_encryption)). 5 | 6 | 1) HideCPU: a novel four-register, byte-based CPU ([see definition here](hidecpu/opcodes.md)). 7 | 8 | To run: 9 | 10 | git clone --recursive https://github.com/mmastrac/oblivious-cpu.git 11 | bin/build.sh 12 | # Run the sort test 13 | bin/hidecpu.sh run hidecpu/samples/sort.asm 14 | # Run the credit-card check digit test 15 | bin/hidecpu.sh run hidecpu/samples/creditcard.asm 16 | 17 | 2) A re-implementation of [ShapeCPU](https://hcrypt.com/shape-cpu/) with a number of optimizations ([see definition here](shapecpu/pseudocode.txt)). 18 | 19 | To run: 20 | 21 | git clone --recursive https://github.com/mmastrac/oblivious-cpu.git 22 | bin/build.sh 23 | # Run the sort test 24 | bin/shapecpu.sh run shapecpu/samples/sort.asm 25 | # Run the credit-card check digit test 26 | bin/shapecpu.sh run shapecpu/samples/creditcard.asm 27 | 28 | Implementation Notes 29 | ==================== 30 | 31 | This project uses a register transfer language built in Java to execute a CPU in either an immediate or a "recording" mode that can be used to construct a graph of XOR, AND and NOT operators. 32 | This approach allows us to optimize the CPU offline, removing redundant operations and reducing the overall gate count of the CPU. The graph can also be exported to a form that can be executed 33 | in an alternate FHE environment (C, etc) rather that in the Java environment provided. 34 | 35 | Optimizations 36 | ============= 37 | 38 | The graph optimizer currently optimizes the following patterns: 39 | 40 | * Unused nodes with no outputs (trimmed) 41 | * Greedy common-subexpression extraction 42 | * Constant folding (x XOR constant, x AND constant) 43 | 44 | The graph optimizer does not optimize the following (yet): 45 | 46 | * !!a -> a 47 | * (!a XOR !b) -> (a XOR b) 48 | * (a XOR a XOR b) -> b 49 | * (a XOR b) AND !(b XOR c) -> (a XOR b) AND (a XOR c) 50 | * (a AND b) XOR (a AND c) -> a AND (b XOR c) 51 | 52 | TODO 53 | ==== 54 | 55 | * Proper documentation 56 | * An implementation of C. Gentry's fully homomorphic system (perhaps through libScarab) 57 | 58 | 59 | Links 60 | ===== 61 | 62 | The original version of ShapeCPU is here: https://hcrypt.com/shape-cpu/ 63 | 64 | License: Apache v2.0 [license](http://www.apache.org/licenses/LICENSE-2.0.html) 65 | 66 | Note that some of the ShapeCPU samples may be under the ShapeCPU license. 67 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/light/StandardState.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import java.util.Map; 4 | 5 | import com.grack.homomorphic.ops.Bit; 6 | import com.grack.homomorphic.ops.State; 7 | import com.grack.homomorphic.ops.Word; 8 | 9 | public class StandardState implements State { 10 | private Map bits; 11 | private Map words; 12 | private Map wordArrays; 13 | private Bit one; 14 | private Bit zero; 15 | private boolean debug; 16 | 17 | public StandardState(Bit one, Bit zero, Map bits, 18 | Map words, Map wordArrays, boolean debug) { 19 | this.one = one; 20 | this.zero = zero; 21 | this.bits = bits; 22 | this.words = words; 23 | this.wordArrays = wordArrays; 24 | this.debug = debug; 25 | } 26 | 27 | public Bit one() { 28 | return one; 29 | }; 30 | 31 | @Override 32 | public Bit zero() { 33 | return zero; 34 | } 35 | 36 | @Override 37 | public Word negativeOne(int width) { 38 | Bit[] bits = new Bit[width]; 39 | for (int i = 0; i < width; i++) 40 | bits[i] = one; 41 | 42 | return new Word(bits); 43 | } 44 | 45 | @Override 46 | public Word getWordRegister(String name) { 47 | if (!words.containsKey(name)) 48 | throw new IllegalArgumentException("Invalid key: " + name); 49 | return words.get(name); 50 | } 51 | 52 | @Override 53 | public Bit getBitRegister(String name) { 54 | if (!bits.containsKey(name)) 55 | throw new IllegalArgumentException("Invalid key: " + name); 56 | return bits.get(name); 57 | } 58 | 59 | @Override 60 | public Word[] getWordArrayRegister(String name) { 61 | if (!wordArrays.containsKey(name)) 62 | throw new IllegalArgumentException("Invalid key: " + name); 63 | return wordArrays.get(name); 64 | } 65 | 66 | @Override 67 | public void setBitRegister(String name, Bit value) { 68 | if (!bits.containsKey(name)) 69 | throw new IllegalArgumentException("Invalid key: " + name); 70 | bits.put(name, value); 71 | } 72 | 73 | @Override 74 | public void setWordRegister(String name, Word value) { 75 | if (!words.containsKey(name)) 76 | throw new IllegalArgumentException("Invalid key: " + name); 77 | words.put(name, value); 78 | } 79 | 80 | @Override 81 | public void setWordArrayRegister(String name, Word[] value) { 82 | if (!wordArrays.containsKey(name)) 83 | throw new IllegalArgumentException("Invalid key: " + name); 84 | wordArrays.put(name, value); 85 | } 86 | 87 | public void debug(Object... things) { 88 | if (!debug) 89 | return; 90 | 91 | for (Object thing : things) { 92 | System.out.print(thing + " "); 93 | } 94 | System.out.println(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/logging/LoggingState.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.logging; 2 | 3 | import java.util.Map; 4 | 5 | import com.grack.homomorphic.ops.Bit; 6 | import com.grack.homomorphic.ops.State; 7 | import com.grack.homomorphic.ops.Word; 8 | 9 | public class LoggingState implements State { 10 | private Map bits; 11 | private Map words; 12 | private Map wordArrays; 13 | private Bit one; 14 | private Bit zero; 15 | private LoggingBitFactory bitFactory; 16 | 17 | public LoggingState(LoggingBitFactory bitFactory, Bit one, Bit zero, Map bits, 18 | Map words, Map wordArrays) { 19 | this.bitFactory = bitFactory; 20 | this.one = one; 21 | this.zero = zero; 22 | this.bits = bits; 23 | this.words = words; 24 | this.wordArrays = wordArrays; 25 | } 26 | 27 | @Override 28 | public Word getWordRegister(String name) { 29 | if (!words.containsKey(name)) 30 | throw new IllegalArgumentException("Invalid key: " + name); 31 | return words.get(name); 32 | } 33 | 34 | @Override 35 | public Bit getBitRegister(String name) { 36 | if (!bits.containsKey(name)) 37 | throw new IllegalArgumentException("Invalid key: " + name); 38 | return bits.get(name); 39 | } 40 | 41 | @Override 42 | public Word[] getWordArrayRegister(String name) { 43 | if (!wordArrays.containsKey(name)) 44 | throw new IllegalArgumentException("Invalid key: " + name); 45 | return wordArrays.get(name); 46 | } 47 | 48 | @Override 49 | public void setBitRegister(String name, Bit value) { 50 | if (!bits.containsKey(name)) 51 | throw new IllegalArgumentException("Invalid key: " + name); 52 | bitFactory.createNamedOutputBit(name, value); 53 | } 54 | 55 | @Override 56 | public void setWordRegister(String name, Word value) { 57 | if (!words.containsKey(name)) 58 | throw new IllegalArgumentException("Invalid key: " + name); 59 | bitFactory.createNamedOutputWord(name, value); 60 | } 61 | 62 | @Override 63 | public void setWordArrayRegister(String name, Word[] value) { 64 | if (!wordArrays.containsKey(name)) 65 | throw new IllegalArgumentException("Invalid key: " + name); 66 | bitFactory.createNamedOutputWordArray(name, value); 67 | } 68 | 69 | @Override 70 | public Bit one() { 71 | return one; 72 | } 73 | 74 | @Override 75 | public Bit zero() { 76 | return zero; 77 | } 78 | 79 | @Override 80 | public Word negativeOne(int width) { 81 | Bit[] bits = new Bit[width]; 82 | for (int i = 0; i < width; i++) 83 | bits[i] = one; 84 | 85 | return new Word(bits); 86 | } 87 | 88 | @Override 89 | public void debug(Object... things) { 90 | // no-op in this mode 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/graph/Node.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | import java.util.ArrayList; 4 | 5 | public abstract class Node { 6 | protected ArrayList in = new ArrayList<>(); 7 | protected ArrayList out = new ArrayList<>(); 8 | 9 | protected void addInput(Node node) { 10 | in.add(node); 11 | node.out.add(this); 12 | } 13 | 14 | protected void removeOutput(Node node) { 15 | out.remove(node); 16 | } 17 | 18 | protected void swapInput(Node from, Node to) { 19 | for (int i = 0; i < in.size(); i++) { 20 | if (in.get(i) == from) { 21 | in.set(i, to); 22 | to.out.add(this); 23 | } 24 | } 25 | } 26 | 27 | public boolean sameInputsAs(Node other) { 28 | ArrayList otherIn = other.in; 29 | 30 | if (in.size() == 1 && otherIn.size() == 1) { 31 | return in.get(0) == otherIn.get(0); 32 | } 33 | 34 | if (in.size() == 2 && otherIn.size() == 2) { 35 | return (in.get(0) == otherIn.get(0) && in.get(1) == otherIn.get(1)) 36 | || (in.get(0) == otherIn.get(1) && in.get(1) == otherIn 37 | .get(0)); 38 | } 39 | 40 | throw new IllegalStateException("Unable to compare > 2 right now"); 41 | } 42 | 43 | /** 44 | * Replace this node with another. 45 | */ 46 | public void replaceWith(Node other) { 47 | for (Node toRedirect : this.outputs()) { 48 | toRedirect.swapInput(this, other); 49 | } 50 | 51 | for (Node toRemoveFrom : this.inputs()) { 52 | toRemoveFrom.removeOutput(this); 53 | } 54 | } 55 | 56 | public void visitIn(NodeVisitor pre, NodeVisitor post) { 57 | boolean visitChildren = true; 58 | if (pre != null) 59 | visitChildren = pre.visit(this); 60 | 61 | if (visitChildren) { 62 | for (Node node : in) { 63 | node.visitIn(pre, post); 64 | } 65 | 66 | if (post != null) 67 | post.visit(this); 68 | } 69 | } 70 | 71 | public void visitOut(NodeVisitor pre, NodeVisitor post) { 72 | boolean visitChildren = true; 73 | if (pre != null) 74 | visitChildren = pre.visit(this); 75 | 76 | if (visitChildren) { 77 | for (Node node : out) { 78 | node.visitOut(pre, post); 79 | } 80 | 81 | if (post != null) 82 | post.visit(this); 83 | } 84 | } 85 | 86 | public Node output(int n) { 87 | return out.get(n); 88 | } 89 | 90 | public Iterable outputs() { 91 | return out; 92 | } 93 | 94 | public int outputCount() { 95 | return out.size(); 96 | } 97 | 98 | public Node input(int n) { 99 | return in.get(n); 100 | } 101 | 102 | public Iterable inputs() { 103 | return in; 104 | } 105 | 106 | public int inputCount() { 107 | return in.size(); 108 | } 109 | 110 | public void remove() { 111 | if (this.out.size() > 0) 112 | throw new IllegalStateException("Can't remove a node with outputs"); 113 | 114 | for (Node node : in) { 115 | node.removeOutput(this); 116 | } 117 | } 118 | 119 | /** 120 | * Creates a duplicate of this node, but without any links. 121 | */ 122 | public abstract Node duplicate(); 123 | } 124 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/light/StandardStateFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.light; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import com.grack.homomorphic.ops.Bit; 7 | import com.grack.homomorphic.ops.NativeBitFactory; 8 | import com.grack.homomorphic.ops.State; 9 | import com.grack.homomorphic.ops.StateFactory; 10 | import com.grack.homomorphic.ops.Word; 11 | 12 | public class StandardStateFactory implements StateFactory { 13 | private static final Map bits = new HashMap<>(); 14 | private static final Map words = new HashMap<>(); 15 | private static final Map wordArrays = new HashMap<>(); 16 | private NativeBitFactory bitFactory; 17 | private Map initialState; 18 | private boolean debug; 19 | 20 | public StandardStateFactory(NativeBitFactory bitFactory, 21 | Map initialState, boolean debug) { 22 | this.bitFactory = bitFactory; 23 | this.initialState = initialState; 24 | this.debug = debug; 25 | } 26 | 27 | @Override 28 | public void allocateWordRegister(String name, int width) { 29 | if (initialState != null && initialState.containsKey(name)) { 30 | Object value = initialState.get(name); 31 | if (value instanceof Number) { 32 | words.put(name, bitFactory.encodeWord( 33 | ((Number) value).intValue(), width)); 34 | } else { 35 | throw new IllegalArgumentException( 36 | "Word register doesn't match with initial value: " 37 | + value); 38 | } 39 | } else { 40 | words.put(name, bitFactory.encodeWord(0, width)); 41 | } 42 | } 43 | 44 | @Override 45 | public void allocateBitRegister(String name) { 46 | if (initialState != null && initialState.containsKey(name)) { 47 | Object value = initialState.get(name); 48 | if (value instanceof Number) { 49 | bits.put(name, 50 | bitFactory.encodeBit(((Number) value).intValue())); 51 | } else { 52 | throw new IllegalArgumentException( 53 | "Bit register doesn't match with initial value: " 54 | + value); 55 | } 56 | } else { 57 | bits.put(name, bitFactory.encodeBit(0)); 58 | } 59 | } 60 | 61 | @Override 62 | public void allocateWordArrayRegister(String name, int width, int size) { 63 | if (initialState != null && initialState.containsKey(name)) { 64 | Object value = initialState.get(name); 65 | if (value instanceof int[]) { 66 | int[] values = (int[]) value; 67 | 68 | Word[] words = new Word[size]; 69 | for (int i = 0; i < size; i++) { 70 | words[i] = bitFactory.encodeWord(i > values.length - 1 ? 0 : values[i], width); 71 | } 72 | wordArrays.put(name, words); 73 | } else { 74 | throw new IllegalArgumentException( 75 | "Word array register doesn't match with initial value: " 76 | + value); 77 | } 78 | } else { 79 | Word[] words = new Word[size]; 80 | for (int i = 0; i < size; i++) { 81 | words[i] = bitFactory.encodeWord(0, width); 82 | } 83 | wordArrays.put(name, words); 84 | } 85 | } 86 | 87 | @Override 88 | public State createState() { 89 | return new StandardState(bitFactory.encodeBit(1), 90 | bitFactory.encodeBit(0), bits, words, wordArrays, debug); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/logging/LoggingBit.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.logging; 2 | 3 | import com.grack.homomorphic.ops.NativeBit; 4 | 5 | public class LoggingBit implements NativeBit { 6 | private LoggingBitFactory bitFactory; 7 | private LoggingBitNodeType type; 8 | private int[] children; 9 | private int nodeIndex; 10 | private String name; 11 | 12 | public LoggingBit(LoggingBitFactory bitFactory, String name, 13 | LoggingBitNodeType type, int[] children) { 14 | this.bitFactory = bitFactory; 15 | this.name = name; 16 | this.type = type; 17 | this.children = children; 18 | this.nodeIndex = bitFactory.register(this); 19 | } 20 | 21 | @Override 22 | public NativeBit xor(NativeBit n) { 23 | return bitFactory.create(null, LoggingBitNodeType.XOR, new int[] { 24 | this.nodeIndex, ((LoggingBit) n).nodeIndex }); 25 | } 26 | 27 | @Override 28 | public NativeBit and(NativeBit n) { 29 | return bitFactory.create(null, LoggingBitNodeType.AND, new int[] { 30 | this.nodeIndex, ((LoggingBit) n).nodeIndex }); 31 | } 32 | 33 | @Override 34 | public NativeBit not() { 35 | return bitFactory.create(null, LoggingBitNodeType.NOT, 36 | new int[] { this.nodeIndex }); 37 | } 38 | 39 | @Override 40 | public NativeBit one() { 41 | return bitFactory.encodeNativeBit(1); 42 | } 43 | 44 | @Override 45 | public NativeBit zero() { 46 | return bitFactory.encodeNativeBit(0); 47 | } 48 | 49 | public String describe() { 50 | switch (type) { 51 | case INPUT: 52 | return Integer.toString(nodeIndex); 53 | case OUTPUT: 54 | return Integer.toString(nodeIndex); 55 | case AND: 56 | return bitFactory.get(children[0]).describe() + " & " 57 | + bitFactory.get(children[1]).describe(); 58 | case XOR: 59 | return bitFactory.get(children[0]).describe() + " ^ " 60 | + bitFactory.get(children[1]).describe(); 61 | case NOT: 62 | return "!" + bitFactory.get(children[0]).describe(); 63 | } 64 | 65 | return ""; 66 | } 67 | 68 | public String toString() { 69 | switch (type) { 70 | case INPUT: 71 | return "IN: " + bitFactory.nameOf(nodeIndex); 72 | case OUTPUT: 73 | return "OUT: " + bitFactory.nameOf(nodeIndex) + " = " + bitFactory.nameOf(children[0]); 74 | case AND: 75 | return bitFactory.nameOf(nodeIndex) + " = " 76 | + bitFactory.nameOf(children[0]) + " & " 77 | + bitFactory.nameOf(children[1]); 78 | case XOR: 79 | return bitFactory.nameOf(nodeIndex) + " = " 80 | + bitFactory.nameOf(children[0]) + " ^ " 81 | + bitFactory.nameOf(children[1]); 82 | case NOT: 83 | return bitFactory.nameOf(nodeIndex) + " = !" 84 | + bitFactory.nameOf(children[0]); 85 | } 86 | 87 | return ""; 88 | } 89 | 90 | public int[] children() { 91 | return children; 92 | } 93 | 94 | public int index() { 95 | return nodeIndex; 96 | } 97 | 98 | public String name() { 99 | return name; 100 | } 101 | 102 | public void name(String name) { 103 | if (this.name != null) 104 | throw new IllegalStateException("This node already has a name"); 105 | this.name = name; 106 | } 107 | 108 | public LoggingBitNodeType type() { 109 | return type; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /hidecpu2/src/test/java/com/grack/hidecpu2/assembler/RunTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.OutputStreamWriter; 10 | import java.io.Writer; 11 | import java.util.HashMap; 12 | 13 | import org.junit.Test; 14 | import org.junit.experimental.theories.ParametersSuppliedBy; 15 | import org.junit.experimental.theories.Theories; 16 | import org.junit.experimental.theories.Theory; 17 | import org.junit.runner.RunWith; 18 | 19 | import com.google.common.base.Charsets; 20 | import com.google.common.io.CharSource; 21 | import com.google.common.io.Resources; 22 | import com.grack.hidecpu2.CPU; 23 | import com.grack.homomorphic.graph.Graph; 24 | import com.grack.homomorphic.light.LightBitFactory; 25 | import com.grack.homomorphic.light.StandardStateFactory; 26 | import com.grack.homomorphic.logging.LoggingBitFactory; 27 | import com.grack.homomorphic.logging.LoggingStateFactory; 28 | import com.grack.homomorphic.ops.State; 29 | import com.grack.homomorphic.ops.StateFactory; 30 | 31 | @RunWith(Theories.class) 32 | public class RunTest { 33 | @Test 34 | public void cpuLogging() throws FileNotFoundException, IOException { 35 | LoggingBitFactory factory = new LoggingBitFactory(); 36 | LoggingStateFactory stateFactory = new LoggingStateFactory(factory); 37 | CPU cpu = new CPU(); 38 | cpu.initialize(factory, stateFactory); 39 | State state = stateFactory.createState(); 40 | cpu.tick(state); 41 | 42 | Graph graph = factory.toGraph(); 43 | graph.optimize(); 44 | 45 | try (Writer w = new OutputStreamWriter(new FileOutputStream( 46 | "/tmp/output.txt"))) { 47 | graph.toC(w); 48 | } 49 | } 50 | 51 | /** 52 | * Attempt to parse all the samples. 53 | */ 54 | @Theory 55 | public void runFile(@ParametersSuppliedBy(AllTests.class) String file) throws IOException { 56 | CharSource src = Resources.asCharSource(getClass().getResource("/" + file), Charsets.UTF_8); 57 | Parser parser = new Parser(src); 58 | Program program = parser.parse(); 59 | Compiler compiler = new Compiler(); 60 | compiler.compile(program); 61 | HashMap initialState = new HashMap<>(); 62 | initialState.put(CPU.MEMORY_CODE, program.getProgram("code")); 63 | initialState.put(CPU.MEMORY_DATA, program.getProgram("data")); 64 | 65 | CPU cpu = new CPU(); 66 | LightBitFactory factory = new LightBitFactory(); 67 | StateFactory stateFactory = new StandardStateFactory(factory, 68 | initialState, false); 69 | State state = stateFactory.createState(); 70 | cpu.initialize(factory, stateFactory); 71 | long lastPc = -1; 72 | for (int i = 0; i < 1000; i++) { 73 | cpu.tick(state); 74 | long pc = factory.extract(state.getWordRegister("pc")); 75 | if (pc == lastPc) { 76 | // dumpMemory(factory, state); 77 | assertEquals("Invalid output in " + file, 99, factory.extract(state.getWordArrayRegister(CPU.MEMORY_DATA)[0])); 78 | System.out.println("XOR count = " + factory.getXorCount()); 79 | System.out.println("AND count = " + factory.getAndCount()); 80 | return; 81 | } 82 | 83 | lastPc = pc; 84 | } 85 | 86 | fail("Ran 10,000 cycles in " + file); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /core/src/test/java/com/grack/homomorphic/fhe/FheMathTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.fhe; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.jscience.mathematics.function.Polynomial; 6 | import org.jscience.mathematics.function.Variable; 7 | import org.jscience.mathematics.number.LargeInteger; 8 | import org.junit.Test; 9 | 10 | public class FheMathTest { 11 | @Test 12 | public void resultantSimple() { 13 | Variable.Local x = new Variable.Local<>("x"); 14 | Polynomial a = Polynomial.valueOf(LargeInteger.ONE, x) 15 | .pow(8).plus(LargeInteger.ONE); 16 | Polynomial b = Polynomial.valueOf(LargeInteger.ZERO, x); 17 | for (int i = 1; i < 4; i++) { 18 | b = b.plus(Polynomial.valueOf(LargeInteger.ONE, x).pow(i) 19 | .times(LargeInteger.valueOf(i))); 20 | } 21 | 22 | assertEquals(6596L, FheMath.resultant(a, b, x).longValue()); 23 | } 24 | 25 | // Resultant[x^8+1, x^7+10x^5+2x^4+99x, x] 26 | @Test 27 | public void resultantBigger() { 28 | Variable.Local x = new Variable.Local<>("x"); 29 | Polynomial oneX = Polynomial.valueOf(LargeInteger.ONE, x); 30 | Polynomial a = oneX.pow(8).plus(LargeInteger.ONE); 31 | Polynomial b = oneX.pow(7) 32 | .plus(oneX.pow(5).times(LargeInteger.valueOf(10))) 33 | .plus(oneX.pow(4).times(LargeInteger.valueOf(2))) 34 | .plus(oneX.pow(1).times(LargeInteger.valueOf(99))); 35 | 36 | assertEquals(9610526820274436L, FheMath.resultant(a, b, x).longValue()); 37 | } 38 | 39 | @Test 40 | public void monicAlready() { 41 | Variable.Local x = new Variable.Local<>("x"); 42 | Polynomial oneX = Polynomial.valueOf(LargeInteger.ONE, x); 43 | Polynomial a = oneX.pow(8).plus(LargeInteger.ONE); 44 | assertEquals(a, FheMath.monic(a, x)); 45 | } 46 | 47 | @Test 48 | public void monicLarge() { 49 | Variable.Local x = new Variable.Local<>("x"); 50 | Polynomial oneX = Polynomial.valueOf(LargeInteger.ONE, x); 51 | Polynomial a = oneX.pow(7).times(LargeInteger.valueOf(2)) 52 | .plus(oneX.pow(5).times(LargeInteger.valueOf(10))) 53 | .plus(oneX.pow(4).times(LargeInteger.valueOf(2))) 54 | .plus(oneX.pow(1).times(LargeInteger.valueOf(50))) 55 | .plus(LargeInteger.valueOf(20)); 56 | Polynomial expected = oneX.pow(7).times(LargeInteger.valueOf(1)) 57 | .plus(oneX.pow(5).times(LargeInteger.valueOf(5))) 58 | .plus(oneX.pow(4).times(LargeInteger.valueOf(1))) 59 | .plus(oneX.pow(1).times(LargeInteger.valueOf(25))) 60 | .plus(LargeInteger.valueOf(10)); 61 | assertEquals(expected, FheMath.monic(a, x)); 62 | } 63 | 64 | @Test 65 | public void monicLargeNoConstant() { 66 | Variable.Local x = new Variable.Local<>("x"); 67 | Polynomial oneX = Polynomial.valueOf(LargeInteger.ONE, x); 68 | Polynomial a = oneX.pow(7).times(LargeInteger.valueOf(2)) 69 | .plus(oneX.pow(5).times(LargeInteger.valueOf(10))) 70 | .plus(oneX.pow(4).times(LargeInteger.valueOf(2))) 71 | .plus(oneX.pow(1).times(LargeInteger.valueOf(50))); 72 | Polynomial expected = oneX.pow(7).times(LargeInteger.valueOf(1)) 73 | .plus(oneX.pow(5).times(LargeInteger.valueOf(5))) 74 | .plus(oneX.pow(4).times(LargeInteger.valueOf(1))) 75 | .plus(oneX.pow(1).times(LargeInteger.valueOf(25))); 76 | assertEquals(expected, FheMath.monic(a, x)); 77 | } 78 | 79 | // PolynomialGCD[x^4+8x^3+21x^2+22x+8, x^3+6x^2+11x+6] = x^2+3x+2 80 | @Test 81 | public void gcdEuclidean() { 82 | // Not yet implemented 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /core/src/test/java/com/grack/homomorphic/BitTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import com.grack.homomorphic.light.LightBitFactory; 9 | import com.grack.homomorphic.ops.Bit; 10 | import com.grack.homomorphic.ops.BitAndBit; 11 | 12 | public class BitTest { 13 | private LightBitFactory factory; 14 | private Bit one; 15 | private Bit zero; 16 | 17 | @Before 18 | public void setup() { 19 | factory = new LightBitFactory(); 20 | one = factory.encodeBit(1); 21 | zero = factory.encodeBit(0); 22 | } 23 | 24 | @Test 25 | public void and() { 26 | assertEquals(1, factory.extract(one.and(one))); 27 | assertEquals(0, factory.extract(one.and(zero))); 28 | assertEquals(0, factory.extract(zero.and(one))); 29 | } 30 | 31 | @Test 32 | public void or() { 33 | assertEquals(0, factory.extract(zero.or(zero))); 34 | assertEquals(1, factory.extract(one.or(one))); 35 | assertEquals(1, factory.extract(one.or(zero))); 36 | assertEquals(1, factory.extract(zero.or(one))); 37 | } 38 | 39 | @Test 40 | public void xor() { 41 | assertEquals(0, factory.extract(one.xor(one))); 42 | assertEquals(1, factory.extract(one.xor(zero))); 43 | assertEquals(1, factory.extract(zero.xor(one))); 44 | } 45 | 46 | @Test 47 | public void halfAdd() { 48 | BitAndBit b1; 49 | 50 | b1 = one.halfAdd(one); 51 | assertEquals(0, factory.extract(b1.getBit1())); 52 | assertEquals(1, factory.extract(b1.getBit2())); 53 | 54 | b1 = one.halfAdd(zero); 55 | assertEquals(1, factory.extract(b1.getBit1())); 56 | assertEquals(0, factory.extract(b1.getBit2())); 57 | 58 | b1 = zero.halfAdd(one); 59 | assertEquals(1, factory.extract(b1.getBit1())); 60 | assertEquals(0, factory.extract(b1.getBit2())); 61 | 62 | b1 = zero.halfAdd(zero); 63 | assertEquals(0, factory.extract(b1.getBit1())); 64 | assertEquals(0, factory.extract(b1.getBit2())); 65 | } 66 | 67 | @Test 68 | public void fullAdd() { 69 | BitAndBit b1; 70 | 71 | b1 = one.fullAdd(zero, zero); 72 | assertEquals(1, factory.extract(b1.getBit1())); 73 | assertEquals(0, factory.extract(b1.getBit2())); 74 | 75 | b1 = one.fullAdd(one, one); 76 | assertEquals(1, factory.extract(b1.getBit1())); 77 | assertEquals(1, factory.extract(b1.getBit2())); 78 | 79 | b1 = one.fullAdd(one, zero); 80 | assertEquals(0, factory.extract(b1.getBit1())); 81 | assertEquals(1, factory.extract(b1.getBit2())); 82 | 83 | b1 = one.fullAdd(zero, one); 84 | assertEquals(0, factory.extract(b1.getBit1())); 85 | assertEquals(1, factory.extract(b1.getBit2())); 86 | 87 | b1 = zero.fullAdd(one, one); 88 | assertEquals(0, factory.extract(b1.getBit1())); 89 | assertEquals(1, factory.extract(b1.getBit2())); 90 | 91 | b1 = zero.fullAdd(one, zero); 92 | assertEquals(1, factory.extract(b1.getBit1())); 93 | assertEquals(0, factory.extract(b1.getBit2())); 94 | 95 | b1 = zero.fullAdd(zero, one); 96 | assertEquals(1, factory.extract(b1.getBit1())); 97 | assertEquals(0, factory.extract(b1.getBit2())); 98 | 99 | b1 = zero.fullAdd(zero, zero); 100 | assertEquals(0, factory.extract(b1.getBit1())); 101 | assertEquals(0, factory.extract(b1.getBit2())); 102 | } 103 | 104 | @Test 105 | public void ifThen() { 106 | assertEquals(1, factory.extract(one.ifThen(one, zero))); 107 | assertEquals(0, factory.extract(one.ifThen(zero, one))); 108 | assertEquals(1, factory.extract(zero.ifThen(zero, one))); 109 | assertEquals(0, factory.extract(zero.ifThen(one, zero))); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /shapecpu/pseudocode.txt: -------------------------------------------------------------------------------- 1 | #define MEMORY_SIZE 256 2 | 3 | word pc; 4 | word ac; 5 | 6 | bit alu_minus; 7 | bit alu_carry; 8 | bit alu_zero; 9 | 10 | word[ARRAY_ROWS] memory; 11 | 12 | (word, bit) add_with_carry(word a, word b, bit carry) { 13 | word res; 14 | bit c = carry; 15 | 16 | for (i : 0..8) { 17 | res[i], c = fulladd(a[i], b[i], c); 18 | } 19 | 20 | return res[i], c; 21 | } 22 | 23 | word memory_read(word addr, int size) { 24 | word b1; 25 | 26 | for (row : 0..MEMORY_SIZE) { 27 | b1 = b1 | (r[row] & memory[row][size - 1:0]); 28 | } 29 | 30 | return b1; 31 | } 32 | 33 | word memory_access(word addr, word target, bit write) { 34 | bit[ARRAY_ROWS] r; 35 | word b1; 36 | 37 | for (row : 0..MEMORY_SIZE) { 38 | r[row] = (addr == row); 39 | memory[row] = (r[row] & write) ? reg : memory[row]; 40 | b1 = b1 | (r[row] & memory[row][7:0]); 41 | } 42 | 43 | return b1; 44 | } 45 | 46 | init() { 47 | pc = 0; 48 | ac = 0; 49 | for (row : 0..MEMORY_SIZE) { 50 | memory[row] = 0; 51 | } 52 | 53 | alu_carry = 0; 54 | alu_zero = 0; 55 | alu_minus = 0; 56 | } 57 | 58 | tick() { 59 | word cmd = memory_read(pc, 13); 60 | word cmd_param = cmd.bits(7, 0); 61 | bit cmd_a = cmd[12]; // Address? 62 | 63 | word load_arg = memory_read(b1, 8); 64 | 65 | // Decode 66 | bit cmd_store = cmd[11:8] == 15; // Store ac to memory 67 | bit cmd_load = cmd[11:8] == 14; // Load memory to ac 68 | bit cmd_ror = cmd[11:8] == 13; // Rotate right through alu_carry 69 | bit cmd_rol = cmd[11:8] == 12; // Rotate left through alu_carry 70 | bit cmd_add = cmd[11:8] == 11; // Add ac to immediate or indirect 71 | bit cmd_clc = cmd[11:8] == 10; // Clear carry 72 | bit cmd_sec = cmd[11:8] == 9; // Set carry 73 | bit cmd_xor = cmd[11:8] == 8; // XOR ac with immediate 74 | bit cmd_and = cmd[11:8] == 7; // AND ac with immediate 75 | bit cmd_or = cmd[11:8] == 6; // OR ac with immediate 76 | bit cmd_beq = cmd[11:8] == 5; // Branch if alu_zero 77 | bit cmd_jmp = cmd[11:8] == 4; // Branch unconditionally 78 | bit cmd_la = cmd[11:8] == 3; // Load indirect 79 | bit cmd_bmi = cmd[11:8] == 2; // Branch if alu_minus 80 | bit cmd_cmp = cmd[11:8] == 1; // Compare ac with immediate or indirect 81 | 82 | // CMP 83 | word b_cmp = !( cmd_a ? load_arg : cmd_param ) + 1 + ac 84 | 85 | // ROL 86 | bit carry_rol = ac[0]; 87 | b_rol[6:0] = ac[7:1] 88 | b_rol[7] = alu_carry; 89 | 90 | // ROR 91 | bit carry_ror = ac[7]; 92 | b_ror[7:1] = ac[6:0]; 93 | b_ror[0] = alu_carry; 94 | 95 | // ADD 96 | b_add_1, carry_1 = add_with_carry(ac, cmd_param, alu_carry); 97 | b_add_2, carry_2 = add_with_carry(ac, load_arg, alu_carry); 98 | word b_add = cmd_a ? b_add_2 : b_add_1; 99 | bit carry_add = cmd_a ? carry_2 : carry_1; 100 | 101 | word load_val = memory_access(b1, ac, cmd_store); 102 | 103 | bit ac_unchanged = cmd_beq | cmd_bmi | cmd_cmp | cmd_jmp | cmd_store | cmd_clc | cmd_sec; 104 | 105 | ac = 106 | cmd_load & b1 | 107 | cmd_ror & b_ror | 108 | cmd_rol & b_rol | 109 | cmd_add & b_add | 110 | cmd_and & (ac & cmd_param) | 111 | cmd_xor & (ac ^ cmd_param) | 112 | cmd_or & (ac | cmd_param) | 113 | cmd_la & load_val | 114 | ac_unchanged & ac; 115 | 116 | alu_zero = (cmd_cmp ? b_cmp == 0 : ac == 0) | (alu_zero & (cmd_bmi | cmd_beq)) 117 | 118 | alu_minus = cmd_cmp ? b_cmp[7] : alu_minus 119 | 120 | alu_carry = 121 | cmd_add ? carry_add : 122 | cmd_rol ? carry_rol : 123 | cmd_ror ? carry_ror : 124 | cmd_clc ? 0 : 125 | cmd_sec ? 1 : 126 | alu_carry; 127 | 128 | word pc_linear = pc + 1 129 | 130 | pc = 131 | cmd_beq ? (alu_zero ? cmd_param : pc_linear) : 132 | cmd_bmi ? (alu_minus ? cmd_param : pc_linear) : 133 | cmd_jmp ? cmd_param : 134 | pc_linear; 135 | } 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /core/src/test/java/com/grack/homomorphic/graph/GraphTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.graph; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | import org.junit.Test; 11 | 12 | import com.grack.homomorphic.logging.LoggingBitFactory; 13 | import com.grack.homomorphic.ops.Bit; 14 | import com.grack.homomorphic.ops.Word; 15 | import com.grack.homomorphic.ops.WordAndBit; 16 | 17 | public class GraphTest { 18 | @SuppressWarnings("unused") 19 | @Test 20 | public void testOptimize() { 21 | Graph graph = new Graph(); 22 | InputNode in1, in2; 23 | graph.addInput(in1 = new InputNode("in1")); 24 | graph.addInput(in2 = new InputNode("in2")); 25 | 26 | AndNode andNode1 = new AndNode(in1, in2); 27 | AndNode andNode2 = new AndNode(in1, in2); 28 | 29 | XorNode unused = new XorNode(andNode1, andNode2); 30 | NotNode unused2 = new NotNode(unused); 31 | 32 | OutputNode out1, out2; 33 | graph.addOutput(out1 = new OutputNode("out1", andNode1)); 34 | graph.addOutput(out2 = new OutputNode("out2", andNode2)); 35 | 36 | assertEquals(3, graph.maxDepth()); 37 | graph.optimize(); 38 | assertEquals(2, graph.maxDepth()); 39 | } 40 | 41 | @Test 42 | public void testFullAdd() throws IOException { 43 | Graph graph = createAdditionGraph(); 44 | assertEquals(14, graph.maxDepth()); 45 | graph.optimize(); 46 | assertEquals(14, graph.maxDepth()); 47 | 48 | try (PrintWriter w = new PrintWriter(System.out)) { 49 | graph.toGraphviz(w); 50 | } 51 | } 52 | 53 | @Test 54 | public void testVisitOut() { 55 | Graph graph = createAdditionGraph(); 56 | 57 | Set nodes = new HashSet<>(); 58 | 59 | graph.visitOut((node) -> { 60 | nodes.add(node); 61 | return true; 62 | }, null); 63 | 64 | assertEquals(graph.nodeCount(), nodes.size()); 65 | } 66 | 67 | @Test 68 | public void testVisitIn() { 69 | Graph graph = createAdditionGraph(); 70 | 71 | Set nodes = new HashSet<>(); 72 | 73 | graph.visitIn((node) -> { 74 | nodes.add(node); 75 | return true; 76 | }, null); 77 | 78 | assertEquals(graph.nodeCount(), nodes.size()); 79 | } 80 | 81 | @Test 82 | public void testVisitTopographical() { 83 | Graph graph = createAdditionGraph(); 84 | 85 | Set nodes = new HashSet<>(); 86 | 87 | // Should visit once and only once 88 | graph.visitTopographical((node) -> { 89 | assertTrue(nodes.add(node)); 90 | }); 91 | 92 | assertEquals(graph.nodeCount(), nodes.size()); 93 | } 94 | 95 | private Graph createAdditionGraph() { 96 | LoggingBitFactory factory = new LoggingBitFactory(); 97 | Bit carryIn = factory.createNamedInputBit("carry"); 98 | 99 | Bit in1a = factory.createNamedInputBit("in1a"); 100 | Bit in1b = factory.createNamedInputBit("in1b"); 101 | Bit in1c = factory.createNamedInputBit("in1c"); 102 | Bit in1d = factory.createNamedInputBit("in1d"); 103 | 104 | Bit in2a = factory.createNamedInputBit("in2a"); 105 | Bit in2b = factory.createNamedInputBit("in2b"); 106 | Bit in2c = factory.createNamedInputBit("in2c"); 107 | Bit in2d = factory.createNamedInputBit("in2d"); 108 | 109 | Word in1 = new Word(new Bit[] { in1a, in1b, in1c, in1d }); 110 | Word in2 = new Word(new Bit[] { in2a, in2b, in2c, in2d }); 111 | 112 | WordAndBit result = in1.addWithCarry(in2, carryIn); 113 | 114 | factory.createNamedOutputBit("outa", result.getWord().bit(3)); 115 | factory.createNamedOutputBit("outb", result.getWord().bit(2)); 116 | factory.createNamedOutputBit("outc", result.getWord().bit(1)); 117 | factory.createNamedOutputBit("outd", result.getWord().bit(0)); 118 | 119 | factory.createNamedOutputBit("carry", result.getBit()); 120 | return factory.toGraph(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /hidecpu/opcodes.md: -------------------------------------------------------------------------------- 1 | HideCPU 2 | ======= 3 | 4 | The HideCPU has four eight-bit registers: r0-r3. r0 and r1 can be used for relative addressing and loads, while 5 | r2 and r3 are for arithmetic only. 6 | 7 | Opcode layout 8 | ============= 9 | 10 | aaaa bb cc dddddddd 11 | a = opcode 12 | b = target register (source for store) 13 | c = source type 14 | d = data 15 | 16 | Source argument 17 | =============== 18 | 19 | 0: constant 20 | 1: [constant] # indirect, constant 21 | 2: [r0 + constant] 22 | 3: [r1 + constant] 23 | 24 | Target argument 25 | =============== 26 | 27 | 0-3: r0 - r3 28 | 29 | Assembler Opcodes 30 | ================= 31 | 32 | The assembler opcodes aren't a one-to-one match with the machine opcodes. 33 | 34 | Most assembler opcodes consist of the form: 35 | 36 | op target, source 37 | 38 | Target is one of the registers, r0-r3. Source is either a constant, a constant-relative load, or a constant 39 | load relative to r0 or r1. 40 | 41 | mov 42 | === 43 | 44 | `mov (r0-r3), [ror|rol|not] (constant|constant-load|r0-relative|r1-relative|r0-r3)` 45 | 46 | Operates as a load, optionally rotating left or right or inverting. If loading from 47 | one register to another, the memory location for the register is used instead. 48 | 49 | `mov (constant-store|r0-relative|r1-relative), (r0|r1|r2|r3)` 50 | 51 | Store operation, placing the contents in memory either in a constant location 52 | or relative to r0/r1. 53 | 54 | Examples: 55 | 56 | `mov r0, ror [r0+10] => r0 = *(r0 + 10) ror 1` 57 | 58 | math 59 | ==== 60 | 61 | `(add|sub|and|or|xor), (constant|constant-load|r0-relative|r1-relative)` 62 | 63 | Loads the source and target, applies a mathematical or binary operation to it, then stores 64 | it back into the target register. 65 | 66 | Examples: 67 | 68 | `add r0, [r0+10] => r0 = r0 + *(r0 + 10)` 69 | 70 | cmp 71 | === 72 | 73 | Compares the source and target registers, setting the minus, and zero flags appropriately. 74 | 75 | Examples: 76 | 77 | ``` 78 | cmp r0, [r0+10] 79 | => minus = r0 < *(r0 + 10), zero = r0 == *(r0 + 10) 80 | ``` 81 | 82 | sec/clc 83 | ======= 84 | 85 | Sets or clears the carry flag explicitly. 86 | 87 | branch/jump/loop 88 | ================ 89 | 90 | Jumps to the source location, conditionally (eg: loop, blt, beq), or unconditionally (jump). 91 | 92 | b[lt|lte|eq|ca|gte|gt|ne|nc] (constant|constant-load|r0-relative|r1-relative) 93 | 94 | Conditional branch based on status registers: alu_minus, alu_zero, alu_carry. 95 | 96 | jump (constant|constant-load|r0-relative|r1-relative) 97 | 98 | Unconditional branch. 99 | 100 | loop (r0-r3), (constant|constant-load|r0-relative|r1-relative) 101 | 102 | Decrements the register and jumps if the register was zero before decrementing. 103 | 104 | Machine Opcodes 105 | =============== 106 | 107 | ``` 108 | 0 load # load \_ mov 109 | 1 store # store | 110 | 2 ror # rotate right | 111 | 3 rol # rotate left | 112 | 4 not # invert bits / <- is this necessary? 113 | 114 | 5 add rX, something # add 115 | 6 sub rX, something # subtract 116 | 7 and rX, something # and 117 | 8 or rX, something # or 118 | 9 xor rX, something # xor 119 | 120 | 10 cmp rX, something # set minus, zero 121 | 11 carry value # set carry 122 | 12 bra flags, mask, target # branch based on flags (minus/zero/carry) 123 | 13 loop r0, target # decrement and jump if not zero 124 | 14 jump target # jump unconditionally to target 125 | 15 unused for now 126 | ``` 127 | 128 | ``` 129 | # Load indirect 130 | mov r0, [r0] 131 | mov r0, label \_ same encoding (load) 132 | mov r0, constant / 133 | mov r0, [label] \__ same encoding (load) 134 | mov r0, [constant] / 135 | mov r0, ror [r0] <- encoded as ror 136 | mov r0, rol [r0] 137 | mov r0, not [r0] 138 | mov [r1], r0 <-- store 139 | ``` 140 | -------------------------------------------------------------------------------- /hidecpu/src/test/java/com/grack/hidecpu/CPUTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.OutputStreamWriter; 9 | import java.io.Writer; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | import com.google.common.base.Charsets; 17 | import com.google.common.io.Resources; 18 | import com.grack.hidecpu.assembler.Compiler; 19 | import com.grack.hidecpu.assembler.Parser; 20 | import com.grack.hidecpu.assembler.Program; 21 | import com.grack.homomorphic.graph.Graph; 22 | import com.grack.homomorphic.light.LightBitFactory; 23 | import com.grack.homomorphic.light.StandardStateFactory; 24 | import com.grack.homomorphic.logging.LoggingBitFactory; 25 | import com.grack.homomorphic.logging.LoggingStateFactory; 26 | import com.grack.homomorphic.ops.State; 27 | import com.grack.homomorphic.ops.StateFactory; 28 | import com.grack.homomorphic.ops.Word; 29 | 30 | public class CPUTest { 31 | private Map initialState; 32 | 33 | @Before 34 | public void setup() throws IOException { 35 | Parser parser = new Parser(Resources.asCharSource(getClass() 36 | .getResource("/creditcard.asm"), Charsets.UTF_8)); 37 | Program program = parser.parse(); 38 | 39 | // System.out.println(program); 40 | 41 | Compiler compiler = new Compiler(); 42 | compiler.compile(program); 43 | 44 | initialState = new HashMap<>(); 45 | initialState.put("memory", program.getProgram()); 46 | } 47 | 48 | @Test 49 | public void runTicks3() { 50 | CPU cpu = new CPU(); 51 | LightBitFactory factory = new LightBitFactory(); 52 | StateFactory stateFactory = new StandardStateFactory(factory, 53 | initialState, false); 54 | State state = stateFactory.createState(); 55 | cpu.initialize(factory, stateFactory); 56 | cpu.tick(state); 57 | cpu.tick(state); 58 | cpu.tick(state); 59 | } 60 | 61 | @Test 62 | public void runUntilDone() { 63 | CPU cpu = new CPU(); 64 | LightBitFactory factory = new LightBitFactory(); 65 | StateFactory stateFactory = new StandardStateFactory(factory, 66 | initialState, false); 67 | State state = stateFactory.createState(); 68 | cpu.initialize(factory, stateFactory); 69 | long lastPc = -1; 70 | for (int i = 0; i < 10000; i++) { 71 | cpu.tick(state); 72 | long pc = factory.extract(state.getWordRegister("pc")); 73 | if (pc == lastPc) { 74 | // dumpMemory(factory, state); 75 | assertEquals(60, factory.extract(state.getWordArrayRegister("memory")[32])); 76 | assertEquals(0, factory.extract(state.getWordArrayRegister("memory")[33])); 77 | System.out.println("XOR count = " + factory.getXorCount()); 78 | System.out.println("AND count = " + factory.getAndCount()); 79 | return; 80 | } 81 | 82 | lastPc = pc; 83 | } 84 | 85 | fail(); 86 | } 87 | 88 | @Test 89 | public void cpuLogging() throws FileNotFoundException, IOException { 90 | LoggingBitFactory factory = new LoggingBitFactory(); 91 | LoggingStateFactory stateFactory = new LoggingStateFactory(factory); 92 | CPU cpu = new CPU(); 93 | cpu.initialize(factory, stateFactory); 94 | State state = stateFactory.createState(); 95 | cpu.tick(state); 96 | 97 | Graph graph = factory.toGraph(); 98 | graph.optimize(); 99 | 100 | try (Writer w = new OutputStreamWriter(new FileOutputStream( 101 | "/tmp/output.txt"))) { 102 | graph.toC(w); 103 | } 104 | } 105 | 106 | private void dumpMemory(LightBitFactory factory, State state) { 107 | Word[] memory = state.getWordArrayRegister("memory"); 108 | for (int j = 0; j < memory.length; j++) { 109 | long mem = factory.extract(memory[j]) & 0xff; 110 | System.out.println(String.format("%3d: %s %5d", j, 111 | memory[j].toString(), mem)); 112 | } 113 | } 114 | 115 | public static void main(String[] args) { 116 | boolean[] bools = new boolean[] { false, true }; 117 | for (boolean a : bools) { 118 | for (boolean b : bools) { 119 | for (boolean c : bools) { 120 | System.out.println(a + " " + b + " " + c + ": " + ((a && b) ^ (a && c)) + " " + (a && (b ^ c))); 121 | } 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/logging/LoggingBitFactory.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.logging; 2 | 3 | import java.util.ArrayList; 4 | 5 | import com.grack.homomorphic.graph.AndNode; 6 | import com.grack.homomorphic.graph.ConstantNode; 7 | import com.grack.homomorphic.graph.Graph; 8 | import com.grack.homomorphic.graph.InputNode; 9 | import com.grack.homomorphic.graph.Node; 10 | import com.grack.homomorphic.graph.NotNode; 11 | import com.grack.homomorphic.graph.OutputNode; 12 | import com.grack.homomorphic.graph.XorNode; 13 | import com.grack.homomorphic.ops.Bit; 14 | import com.grack.homomorphic.ops.NativeBit; 15 | import com.grack.homomorphic.ops.NativeBitFactory; 16 | import com.grack.homomorphic.ops.Word; 17 | 18 | public class LoggingBitFactory implements NativeBitFactory { 19 | private int index; 20 | private ArrayList bits = new ArrayList<>(); 21 | 22 | int nextIndex() { 23 | return index++; 24 | } 25 | 26 | public LoggingBit get(int index) { 27 | return bits.get(index); 28 | } 29 | 30 | @Override 31 | public NativeBit encodeNativeBit(int bit) { 32 | if (bit == 0) 33 | return encodeNamedInputBit("zero"); 34 | if (bit == 1) 35 | return encodeNamedInputBit("one"); 36 | throw new IllegalArgumentException("bit"); 37 | } 38 | 39 | public NativeBit encodeNamedInputBit(String name) { 40 | return create(name, LoggingBitNodeType.INPUT, new int[0]); 41 | } 42 | 43 | public NativeBit encodeNamedOutputBit(String name, NativeBit value) { 44 | return create(name, LoggingBitNodeType.OUTPUT, new int[] { ((LoggingBit) value).index() }); 45 | } 46 | 47 | public Bit createNamedInputBit(String name) { 48 | return new Bit(encodeNamedInputBit(name)); 49 | } 50 | 51 | public Bit createNamedOutputBit(String name, Bit value) { 52 | return new Bit(encodeNamedOutputBit(name, value.nativeBit())); 53 | } 54 | 55 | public Word createNamedInputWord(String name, int width) { 56 | Bit[] bits = new Bit[width]; 57 | for (int i = 0; i < width; i++) 58 | bits[i] = createNamedInputBit(name + ":" + i); 59 | return new Word(bits); 60 | } 61 | 62 | public Word createNamedOutputWord(String name, Word value) { 63 | Bit[] bits = new Bit[value.size()]; 64 | for (int i = 0; i < value.size(); i++) 65 | bits[i] = createNamedOutputBit(name + ":" + i, value.bit(i)); 66 | return new Word(bits); 67 | } 68 | 69 | public Word[] createNamedInputWordArray(String name, int width, int size) { 70 | Word[] words = new Word[size]; 71 | for (int i = 0; i < size; i++) 72 | words[i] = createNamedInputWord(name + ":" + i, width); 73 | return words; 74 | } 75 | 76 | public Word[] createNamedOutputWordArray(String name, Word[] value) { 77 | Word[] words = new Word[value.length]; 78 | for (int i = 0; i < value.length; i++) 79 | words[i] = createNamedOutputWord(name + ":" + i, value[i]); 80 | return words; 81 | } 82 | 83 | public int nodeCount() { 84 | return bits.size(); 85 | } 86 | 87 | int register(LoggingBit loggingBit) { 88 | int idx = bits.size(); 89 | bits.add(loggingBit); 90 | return idx; 91 | } 92 | 93 | public NativeBit create(String name, LoggingBitNodeType type, int[] children) { 94 | return new LoggingBit(this, name, type, children); 95 | } 96 | 97 | public String nameOf(int idx) { 98 | LoggingBit bit = get(idx); 99 | if (bit.name() != null) 100 | return bit.name(); 101 | 102 | return Integer.toString(bit.index()); 103 | } 104 | 105 | public Graph toGraph() { 106 | Graph graph = new Graph(); 107 | ArrayList nodes = new ArrayList<>(); 108 | for (LoggingBit bit : bits) { 109 | switch (bit.type()) { 110 | case INPUT: { 111 | InputNode inputNode; 112 | if (bit.name().equals("zero")) 113 | inputNode = new ConstantNode("zero", 0); 114 | else if (bit.name().equals("one")) 115 | inputNode = new ConstantNode("one", 1); 116 | else 117 | inputNode = new InputNode(bit.name()); 118 | graph.addInput(inputNode); 119 | nodes.add(inputNode); 120 | break; 121 | } 122 | case OUTPUT: { 123 | OutputNode outputNode = new OutputNode(bit.name(), nodes.get(bit.children()[0])); 124 | graph.addOutput(outputNode); 125 | nodes.add(outputNode); 126 | break; 127 | } 128 | case AND: { 129 | AndNode andNode = new AndNode(nodes.get(bit.children()[0]), nodes.get(bit.children()[1])); 130 | nodes.add(andNode); 131 | break; 132 | } 133 | case XOR: { 134 | XorNode xorNode = new XorNode(nodes.get(bit.children()[0]), nodes.get(bit.children()[1])); 135 | nodes.add(xorNode); 136 | break; 137 | } 138 | case NOT: { 139 | NotNode notNode = new NotNode(nodes.get(bit.children()[0])); 140 | nodes.add(notNode); 141 | } 142 | } 143 | } 144 | return graph; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Line.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | public class Line { 4 | private String label; 5 | private Opcode opcode; 6 | private Value value; 7 | private OpSource source; 8 | private OpTarget target; 9 | private BranchType branchType; 10 | 11 | public Line(String label) { 12 | this.label = label; 13 | } 14 | 15 | public Line(String label, Opcode opcode, OpSource source, OpTarget target, Value value) { 16 | this.label = label; 17 | this.opcode = opcode; 18 | this.source = source; 19 | this.target = target; 20 | this.value = value; 21 | } 22 | 23 | public Line(Opcode opcode, OpSource source, OpTarget target, Value value) { 24 | this.opcode = opcode; 25 | this.source = source; 26 | this.target = target; 27 | this.value = value; 28 | } 29 | 30 | public Line(String label, Opcode opcode, BranchType branchType, Value value) { 31 | this.label = label; 32 | this.opcode = opcode; 33 | this.branchType = branchType; 34 | this.value = value; 35 | } 36 | 37 | public Line(Opcode opcode, BranchType branchType, Value value) { 38 | this.opcode = opcode; 39 | this.branchType = branchType; 40 | this.value = value; 41 | } 42 | 43 | public Line(Value value) { 44 | this.opcode = Opcode.DATA; 45 | this.source = OpSource.CONSTANT; 46 | this.target = OpTarget.R0; 47 | this.value = value; 48 | } 49 | 50 | public Line(String label, Value value) { 51 | this.label = label; 52 | this.opcode = Opcode.DATA; 53 | this.source = OpSource.CONSTANT; 54 | this.target = OpTarget.R0; 55 | this.value = value; 56 | } 57 | 58 | public String getLabel() { 59 | return label; 60 | } 61 | 62 | public void setLabel(String label) { 63 | this.label = label; 64 | } 65 | 66 | public Opcode getOpcode() { 67 | return opcode; 68 | } 69 | 70 | public void setOpcode(Opcode opcode) { 71 | this.opcode = opcode; 72 | } 73 | 74 | public OpSource getSource() { 75 | return source; 76 | } 77 | 78 | public OpTarget getTarget() { 79 | return target; 80 | } 81 | 82 | public Value getValue() { 83 | return value; 84 | } 85 | 86 | public void setValue(Value value) { 87 | this.value = value; 88 | } 89 | 90 | public boolean isEmpty() { 91 | return label == null && opcode == null; 92 | } 93 | 94 | public int[] assemble() { 95 | if (opcode == Opcode.DATA) 96 | return new int[] { (Integer)value.getValue() }; 97 | 98 | int op = 0; 99 | op |= opcode.ordinal() << 4; 100 | op |= (branchType == null) ? 0 : (branchType.ordinal() << 0); 101 | op |= (target == null) ? 0 : (target.ordinal() << 2); 102 | op |= (source == null) ? 0 : (source.ordinal() << 0); 103 | 104 | int val = 0; 105 | val |= (int) (value == null ? 0 : value.getValue()); 106 | 107 | return new int[] { val, op }; 108 | } 109 | 110 | @Override 111 | public String toString() { 112 | return toString(-1); 113 | } 114 | 115 | public String toString(int line) { 116 | // Empty line 117 | if (isEmpty()) 118 | return ""; 119 | 120 | String s = label == null ? "" : label + ":"; 121 | if (opcode != null) { 122 | if (label != null) 123 | s += '\n'; 124 | if (line != -1) 125 | s += line; 126 | s += '\t'; 127 | 128 | String src = ""; 129 | if (source != null) { 130 | switch (source) { 131 | case CONSTANT: 132 | src = value.toString(); 133 | break; 134 | case CONSTANT_LOAD: 135 | src = '[' + value.toString() + ']'; 136 | break; 137 | case R0_RELATIVE_LOAD: 138 | src = "[r0 + " + value.toString() + ']'; 139 | break; 140 | case R1_RELATIVE_LOAD: 141 | src = "[r1 + " + value.toString() + ']'; 142 | break; 143 | } 144 | } 145 | 146 | switch (opcode) { 147 | case LOAD: 148 | s += "mov\t" + target.name().toLowerCase() + ", " + src; 149 | break; 150 | case STORE: 151 | s += "mov\t" + src + ", " + target.name().toLowerCase(); 152 | break; 153 | case ROL: 154 | case ROR: 155 | case NOT: 156 | s += "mov\t" + target.name().toLowerCase() + ", " 157 | + opcode.name().toLowerCase() + " " + src; 158 | break; 159 | case BRA: 160 | s += "b" + branchType.name().toLowerCase() + "\t" 161 | + value.toString(); 162 | break; 163 | case JUMP: 164 | case DATA: 165 | s += opcode.name().toLowerCase() + "\t" + src; 166 | break; 167 | case CARRY: 168 | if ((int)value.getValue() == 0) 169 | s += "clc"; 170 | else 171 | s += "sec"; 172 | break; 173 | default: 174 | s += opcode.name().toLowerCase() + "\t" 175 | + target.name().toLowerCase() + ", " + src; 176 | } 177 | } 178 | 179 | return s; 180 | } 181 | 182 | public int size() { 183 | if (opcode == null) 184 | return 0; 185 | return opcode == Opcode.DATA ? 1 : 2; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /shapecpu/src/test/resources/com/grack/shapecpu/sort_output.txt: -------------------------------------------------------------------------------- 1 | 0 0 0 1 0 0 0 0 0 0 1 1 1 0 4 2 | 1 1 0 1 0 0 0 0 0 0 1 1 1 0 5 3 | 2 1 0 1 0 0 0 0 0 0 1 1 1 0 5 4 | 3 0 1 1 0 0 0 0 0 0 1 1 1 0 6 5 | 4 1 0 0 1 0 0 0 0 0 1 1 1 0 9 6 | 5 1 0 1 0 0 0 0 0 0 1 1 1 0 5 7 | 6 0 0 1 0 0 0 0 0 0 1 1 1 0 4 8 | 7 1 0 1 0 0 0 0 0 0 1 1 1 0 5 9 | 8 0 1 1 0 0 0 0 0 0 1 1 1 0 6 10 | 9 0 0 0 0 0 0 0 0 0 1 1 1 0 0 11 | 10 0 1 1 0 0 0 0 0 1 1 0 0 1 6 12 | 11 0 0 1 0 1 0 0 0 1 1 1 1 1 20 13 | 12 1 1 1 0 1 0 0 0 1 1 1 1 1 23 14 | 13 0 1 0 1 1 0 0 0 1 1 1 1 1 26 15 | 14 1 1 1 0 0 0 0 0 1 1 0 0 1 7 16 | 15 1 0 1 0 1 0 0 0 1 1 1 1 1 21 17 | 16 1 0 0 1 1 0 0 0 1 1 1 1 1 25 18 | 17 0 0 1 1 1 0 0 0 1 1 1 1 1 28 19 | 18 0 0 0 0 0 0 0 0 0 1 1 1 0 0 20 | 19 1 0 0 1 0 0 0 0 1 1 1 1 1 9 21 | 20 1 1 0 0 0 0 0 0 1 1 0 0 1 3 22 | 21 0 0 1 0 0 0 0 0 1 0 0 0 1 4 23 | 22 1 1 1 1 1 0 0 0 0 1 0 0 0 31 24 | 23 1 1 0 0 0 0 0 0 1 1 0 0 1 3 25 | 24 0 0 0 1 0 0 0 0 1 1 1 1 1 8 26 | 25 0 0 1 0 0 0 0 0 1 1 0 0 1 4 27 | 26 1 1 0 0 0 0 0 0 1 1 1 1 1 3 28 | 27 0 0 0 1 0 0 0 0 1 1 0 0 1 8 29 | 28 0 0 1 0 0 0 0 0 1 1 1 1 1 4 30 | 29 1 0 0 0 0 0 0 0 0 1 1 1 0 1 31 | 30 1 0 0 1 0 0 0 0 1 1 1 1 1 9 32 | 31 0 1 1 0 0 0 0 0 1 1 0 0 1 6 33 | 32 0 0 0 0 0 0 0 0 0 1 0 1 0 0 34 | 33 1 0 0 0 0 0 0 0 1 1 0 1 0 1 35 | 34 0 1 1 0 0 0 0 0 1 1 1 1 1 6 36 | 35 1 1 1 0 0 0 0 0 1 1 0 0 1 7 37 | 36 0 0 0 0 0 0 0 0 0 1 0 1 0 0 38 | 37 1 0 0 0 0 0 0 0 1 1 0 1 0 1 39 | 38 1 1 1 0 0 0 0 0 1 1 1 1 1 7 40 | 39 1 0 1 0 0 0 0 0 1 0 0 0 1 5 41 | 40 0 1 0 1 0 1 0 0 1 0 1 0 0 42 42 | 41 0 1 0 1 0 0 0 0 0 0 1 0 0 10 43 | 42 1 0 0 1 0 0 0 0 1 1 0 0 1 9 44 | 43 1 0 0 0 1 1 0 0 1 0 1 0 0 49 45 | 44 0 0 0 0 0 0 0 0 0 1 1 1 0 0 46 | 45 0 1 1 0 0 0 0 0 1 1 1 1 1 6 47 | 46 1 0 0 0 0 0 0 0 0 1 1 1 0 1 48 | 47 1 1 1 0 0 0 0 0 1 1 1 1 1 7 49 | 48 0 1 0 1 0 0 0 0 0 0 1 0 0 10 50 | 49 1 0 0 0 1 1 0 0 0 0 1 0 0 49 51 | 50 0 0 0 0 0 0 0 0 0 0 0 0 0 0 52 | 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 53 | 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 | 53 0 0 0 0 0 0 0 0 0 0 0 0 0 0 55 | 54 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 | 55 0 0 0 0 0 0 0 0 0 0 0 0 0 0 57 | 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 58 | 57 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 | 58 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 | 59 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 | 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 62 | 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 63 | 62 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 | 63 0 0 0 0 0 0 0 0 0 0 0 0 0 0 65 | 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 | 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 67 | 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 68 | 67 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 | 68 0 0 0 0 0 0 0 0 0 0 0 0 0 0 70 | 69 0 0 0 0 0 0 0 0 0 0 0 0 0 0 71 | 70 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 | 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 73 | 72 0 0 0 0 0 0 0 0 0 0 0 0 0 0 74 | 73 0 0 0 0 0 0 0 0 0 0 0 0 0 0 75 | 74 0 0 0 0 0 0 0 0 0 0 0 0 0 0 76 | 75 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 | 76 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 | 77 0 0 0 0 0 0 0 0 0 0 0 0 0 0 79 | 78 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 | 79 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81 | 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 82 | 81 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 | 82 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 | 83 0 0 0 0 0 0 0 0 0 0 0 0 0 0 85 | 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 86 | 85 0 0 0 0 0 0 0 0 0 0 0 0 0 0 87 | 86 0 0 0 0 0 0 0 0 0 0 0 0 0 0 88 | 87 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 | 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 | 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 91 | 90 0 0 0 0 0 0 0 0 0 0 0 0 0 0 92 | 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 93 | 92 0 0 0 0 0 0 0 0 0 0 0 0 0 0 94 | 93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 95 | 94 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 | 95 0 0 0 0 0 0 0 0 0 0 0 0 0 0 97 | 96 0 0 0 0 0 0 0 0 0 0 0 0 0 0 98 | 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 | 98 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 | 99 0 0 0 0 0 0 0 0 0 0 0 0 0 0 101 | 100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 102 | 101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 103 | 102 0 0 0 0 0 0 0 0 0 0 0 0 0 0 104 | 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 105 | 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 106 | 105 0 0 0 0 0 0 0 0 0 0 0 0 0 0 107 | 106 0 0 0 0 0 0 0 0 0 0 0 0 0 0 108 | 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 109 | 108 0 0 0 0 0 0 0 0 0 0 0 0 0 0 110 | 109 0 0 0 0 0 0 0 0 0 0 0 0 0 0 111 | 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 | 111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 113 | 112 0 0 0 0 0 0 0 0 0 0 0 0 0 0 114 | 113 0 0 0 0 0 0 0 0 0 0 0 0 0 0 115 | 114 0 0 0 0 0 0 0 0 0 0 0 0 0 0 116 | 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 | 116 0 0 0 0 0 0 0 0 0 0 0 0 0 0 118 | 117 0 0 0 0 0 0 0 0 0 0 0 0 0 0 119 | 118 0 0 0 0 0 0 0 0 0 0 0 0 0 0 120 | 119 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 | 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 122 | 121 0 0 0 0 0 0 0 0 0 0 0 0 0 0 123 | 122 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 | 123 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 | 124 0 0 0 0 0 0 0 0 0 0 0 0 0 0 126 | 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 | 126 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 | 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 129 | 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 130 | 129 0 0 0 0 0 0 0 0 0 0 0 0 0 0 131 | 130 0 0 0 0 0 0 0 0 0 0 0 0 0 0 132 | 131 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 | 132 0 0 0 0 0 0 0 0 0 0 0 0 0 0 134 | -------------------------------------------------------------------------------- /shapecpu/src/test/resources/com/grack/shapecpu/creditcard_output.txt: -------------------------------------------------------------------------------- 1 | 0 0 1 0 1 0 1 1 0 1 1 0 0 1 106 2 | 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 3 | 2 0 1 0 1 0 1 1 0 1 1 1 1 1 106 4 | 3 0 0 1 1 0 1 1 0 1 1 0 0 1 108 5 | 4 0 0 0 0 0 0 0 0 0 0 1 1 0 0 6 | 5 0 0 1 1 0 1 1 0 1 1 1 1 1 108 7 | 6 0 1 1 1 0 1 1 0 1 1 0 0 1 110 8 | 7 0 0 0 0 0 0 0 0 0 0 1 1 0 0 9 | 8 0 1 1 1 0 1 1 0 1 1 1 1 1 110 10 | 9 0 0 0 0 1 1 1 0 1 1 0 0 1 112 11 | 10 0 0 0 0 0 0 0 0 0 0 1 1 0 0 12 | 11 0 0 0 0 1 1 1 0 1 1 1 1 1 112 13 | 12 0 1 0 0 1 1 1 0 1 1 0 0 1 114 14 | 13 0 0 0 0 0 0 0 0 0 0 1 1 0 0 15 | 14 0 1 0 0 1 1 1 0 1 1 1 1 1 114 16 | 15 0 0 1 0 1 1 1 0 1 1 0 0 1 116 17 | 16 0 0 0 0 0 0 0 0 0 0 1 1 0 0 18 | 17 0 0 1 0 1 1 1 0 1 1 1 1 1 116 19 | 18 0 1 1 0 1 1 1 0 1 1 0 0 1 118 20 | 19 0 0 0 0 0 0 0 0 0 0 1 1 0 0 21 | 20 0 1 1 0 1 1 1 0 1 1 1 1 1 118 22 | 21 0 0 0 1 1 1 1 0 1 1 0 0 1 120 23 | 22 0 0 0 0 0 0 0 0 0 0 1 1 0 0 24 | 23 0 0 0 1 1 1 1 0 1 1 1 1 1 120 25 | 24 0 1 0 1 0 1 1 0 1 1 0 0 1 106 26 | 25 0 1 0 1 0 0 0 0 1 0 0 0 0 10 27 | 26 0 1 1 1 1 0 0 0 0 1 0 0 0 30 28 | 27 0 0 0 0 0 0 0 0 0 1 0 1 0 0 29 | 28 1 1 1 0 1 1 1 1 1 1 0 1 0 247 30 | 29 0 1 0 1 0 1 1 0 1 1 1 1 1 106 31 | 30 0 0 1 1 0 1 1 0 1 1 0 0 1 108 32 | 31 0 1 0 1 0 0 0 0 1 0 0 0 0 10 33 | 32 0 0 1 0 0 1 0 0 0 1 0 0 0 36 34 | 33 0 0 0 0 0 0 0 0 0 1 0 1 0 0 35 | 34 1 1 1 0 1 1 1 1 1 1 0 1 0 247 36 | 35 0 0 1 1 0 1 1 0 1 1 1 1 1 108 37 | 36 0 1 1 1 0 1 1 0 1 1 0 0 1 110 38 | 37 0 1 0 1 0 0 0 0 1 0 0 0 0 10 39 | 38 0 1 0 1 0 1 0 0 0 1 0 0 0 42 40 | 39 0 0 0 0 0 0 0 0 0 1 0 1 0 0 41 | 40 1 1 1 0 1 1 1 1 1 1 0 1 0 247 42 | 41 0 1 1 1 0 1 1 0 1 1 1 1 1 110 43 | 42 0 0 0 0 1 1 1 0 1 1 0 0 1 112 44 | 43 0 1 0 1 0 0 0 0 1 0 0 0 0 10 45 | 44 0 0 0 0 1 1 0 0 0 1 0 0 0 48 46 | 45 0 0 0 0 0 0 0 0 0 1 0 1 0 0 47 | 46 1 1 1 0 1 1 1 1 1 1 0 1 0 247 48 | 47 0 0 0 0 1 1 1 0 1 1 1 1 1 112 49 | 48 0 1 0 0 1 1 1 0 1 1 0 0 1 114 50 | 49 0 1 0 1 0 0 0 0 1 0 0 0 0 10 51 | 50 0 1 1 0 1 1 0 0 0 1 0 0 0 54 52 | 51 0 0 0 0 0 0 0 0 0 1 0 1 0 0 53 | 52 1 1 1 0 1 1 1 1 1 1 0 1 0 247 54 | 53 0 1 0 0 1 1 1 0 1 1 1 1 1 114 55 | 54 0 0 1 0 1 1 1 0 1 1 0 0 1 116 56 | 55 0 1 0 1 0 0 0 0 1 0 0 0 0 10 57 | 56 0 0 1 1 1 1 0 0 0 1 0 0 0 60 58 | 57 0 0 0 0 0 0 0 0 0 1 0 1 0 0 59 | 58 1 1 1 0 1 1 1 1 1 1 0 1 0 247 60 | 59 0 0 1 0 1 1 1 0 1 1 1 1 1 116 61 | 60 0 1 1 0 1 1 1 0 1 1 0 0 1 118 62 | 61 0 1 0 1 0 0 0 0 1 0 0 0 0 10 63 | 62 0 1 0 0 0 0 1 0 0 1 0 0 0 66 64 | 63 0 0 0 0 0 0 0 0 0 1 0 1 0 0 65 | 64 1 1 1 0 1 1 1 1 1 1 0 1 0 247 66 | 65 0 1 1 0 1 1 1 0 1 1 1 1 1 118 67 | 66 0 0 0 1 1 1 1 0 1 1 0 0 1 120 68 | 67 0 1 0 1 0 0 0 0 1 0 0 0 0 10 69 | 68 0 0 0 1 0 0 1 0 0 1 0 0 0 72 70 | 69 0 0 0 0 0 0 0 0 0 1 0 1 0 0 71 | 70 1 1 1 0 1 1 1 1 1 1 0 1 0 247 72 | 71 0 0 0 1 1 1 1 0 1 1 1 1 1 120 73 | 72 0 0 0 0 0 0 0 0 0 1 0 1 0 0 74 | 73 0 1 0 1 0 1 1 0 1 1 0 0 1 106 75 | 74 0 0 1 1 0 1 1 0 1 1 0 1 1 108 76 | 75 0 1 1 1 0 1 1 0 1 1 0 1 1 110 77 | 76 0 0 0 0 1 1 1 0 1 1 0 1 1 112 78 | 77 0 1 0 0 1 1 1 0 1 1 0 1 1 114 79 | 78 0 0 1 0 1 1 1 0 1 1 0 1 1 116 80 | 79 0 1 1 0 1 1 1 0 1 1 0 1 1 118 81 | 80 0 0 0 1 1 1 1 0 1 1 0 1 1 120 82 | 81 1 0 1 0 0 1 1 0 1 1 1 1 1 101 83 | 82 0 0 0 0 0 0 0 0 0 1 0 1 0 0 84 | 83 1 1 0 1 0 1 1 0 1 1 0 0 1 107 85 | 84 1 0 1 1 0 1 1 0 1 1 0 1 1 109 86 | 85 1 1 1 1 0 1 1 0 1 1 0 1 1 111 87 | 86 1 0 0 0 1 1 1 0 1 1 0 1 1 113 88 | 87 1 1 0 0 1 1 1 0 1 1 0 1 1 115 89 | 88 1 0 1 0 1 1 1 0 1 1 0 1 1 117 90 | 89 1 1 1 0 1 1 1 0 1 1 0 1 1 119 91 | 90 0 1 1 0 0 1 1 0 1 1 1 1 1 102 92 | 91 1 0 1 0 0 1 1 0 1 1 0 1 1 101 93 | 92 1 1 1 0 0 1 1 0 1 1 1 1 1 103 94 | 93 0 0 0 1 0 1 1 0 1 1 1 1 1 104 95 | 94 0 0 0 0 0 0 0 0 0 1 0 1 0 0 96 | 95 0 1 1 0 1 1 1 1 1 1 0 1 0 246 97 | 96 0 1 0 1 0 0 0 0 1 0 0 0 0 10 98 | 97 1 1 0 0 0 1 1 0 0 1 0 0 0 99 99 | 98 0 1 1 1 1 0 1 0 0 0 1 0 0 94 100 | 99 0 0 0 1 0 1 1 0 1 1 1 1 1 104 101 | 100 0 0 1 0 0 1 1 0 0 0 1 0 0 100 102 | 101 1 0 0 0 1 0 0 0 0 1 1 1 0 17 103 | 102 1 0 0 0 0 1 0 0 0 1 1 1 0 33 104 | 103 0 1 0 0 1 1 0 0 0 1 1 1 0 50 105 | 104 0 0 0 0 0 0 0 0 0 1 1 1 0 0 106 | 105 1 1 0 0 0 1 1 0 0 1 1 1 0 99 107 | 106 1 0 0 0 0 0 0 0 0 1 1 1 0 1 108 | 107 0 0 1 0 0 0 0 0 0 1 1 1 0 4 109 | 108 1 0 0 1 0 0 0 0 0 1 1 1 0 9 110 | 109 1 1 1 0 0 0 0 0 0 1 1 1 0 7 111 | 110 0 0 0 0 0 0 0 0 0 1 1 1 0 0 112 | 111 1 1 0 0 0 0 0 0 0 1 1 1 0 3 113 | 112 1 1 0 0 0 0 0 0 0 1 1 1 0 3 114 | 113 1 0 1 0 0 0 0 0 0 1 1 1 0 5 115 | 114 0 0 0 0 0 0 0 0 0 1 1 1 0 0 116 | 115 0 1 0 0 0 0 0 0 0 1 1 1 0 2 117 | 116 0 1 0 0 0 0 0 0 0 1 1 1 0 2 118 | 117 0 1 1 0 0 0 0 0 0 1 1 1 0 6 119 | 118 0 1 0 0 0 0 0 0 0 1 1 1 0 2 120 | 119 0 1 1 0 0 0 0 0 0 1 1 1 0 6 121 | 120 0 0 0 0 0 0 0 0 0 1 1 1 0 0 122 | 121 0 0 0 0 0 0 0 0 0 1 1 1 0 0 123 | 122 0 0 0 0 0 0 0 0 0 0 0 0 0 0 124 | 123 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125 | 124 0 0 0 0 0 0 0 0 0 0 0 0 0 0 126 | 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 | 126 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 | 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 129 | 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 130 | 129 0 0 0 0 0 0 0 0 0 0 0 0 0 0 131 | 130 0 0 0 0 0 0 0 0 0 0 0 0 0 0 132 | 131 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 | 132 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -------------------------------------------------------------------------------- /core/src/main/java/com/grack/homomorphic/fhe/FheMath.java: -------------------------------------------------------------------------------- 1 | package com.grack.homomorphic.fhe; 2 | 3 | import org.jscience.mathematics.function.Constant; 4 | import org.jscience.mathematics.function.Polynomial; 5 | import org.jscience.mathematics.function.Term; 6 | import org.jscience.mathematics.function.Variable; 7 | import org.jscience.mathematics.number.LargeInteger; 8 | 9 | public class FheMath { 10 | public static final Polynomial ZERO_POLY = Constant.valueOf(LargeInteger.ZERO); 11 | 12 | /** 13 | * Slow, recursive determinant. 14 | * 15 | * This will be replaced by something better. 16 | */ 17 | public static LargeInteger determinant(LargeInteger[][] matrix) { 18 | LargeInteger sum = LargeInteger.ZERO; 19 | LargeInteger s; 20 | if (matrix.length == 1) { 21 | return (matrix[0][0]); 22 | } 23 | for (int i = 0; i < matrix.length; i++) { 24 | LargeInteger[][] smaller = new LargeInteger[matrix.length - 1][matrix.length - 1]; 25 | for (int a = 1; a < matrix.length; a++) { 26 | for (int b = 0; b < matrix.length; b++) { 27 | if (b < i) { 28 | smaller[a - 1][b] = matrix[a][b]; 29 | } else if (b > i) { 30 | smaller[a - 1][b - 1] = matrix[a][b]; 31 | } 32 | } 33 | } 34 | 35 | if (i % 2 == 0) { 36 | s = LargeInteger.ONE; 37 | } else { 38 | s = LargeInteger.ONE.opposite(); 39 | } 40 | 41 | sum = sum.plus(s.times(matrix[0][i]).times(determinant(smaller))); 42 | } 43 | return (sum); 44 | } 45 | 46 | public static LargeInteger determinantFast(LargeInteger[][] a) { 47 | int n = a.length; 48 | LargeInteger[][] b = new LargeInteger[n][n]; 49 | for (int i = 0; i < n; i++) 50 | for (int j = 0; j < n; j++) 51 | b[i][j] = a[i][j]; 52 | 53 | int sign = 1; 54 | int[] pow = new int[n]; 55 | for (int i = 0; i < n; ++i) { 56 | int k = i; 57 | for (int j = i + 1; j < n; ++j) { 58 | if (b[k][i].isZero() || !b[j][i].isZero() && b[k][i].abs().compareTo(b[j][i].abs()) > 0) { 59 | k = j; 60 | } 61 | } 62 | if (b[k][i].isZero()) 63 | return LargeInteger.ZERO; 64 | if (i != k) { 65 | sign = -sign; 66 | LargeInteger[] t = b[i]; 67 | b[i] = b[k]; 68 | b[k] = t; 69 | } 70 | ++pow[i]; 71 | for (int j = i + 1; j < n; ++j) 72 | if (!b[j][i].isZero()) { 73 | for (int p = i + 1; p < n; ++p) { 74 | b[j][p] = b[j][p].times(b[i][i]).minus(b[i][p].times(b[j][i])); 75 | } 76 | --pow[i]; 77 | } 78 | } 79 | LargeInteger det = LargeInteger.ONE; 80 | for (int i = 0; i < n; i++) 81 | if (pow[i] > 0) 82 | det = det.times(b[i][i].pow(pow[i])); 83 | for (int i = 0; i < n; i++) 84 | if (pow[i] < 0) 85 | det = det.divide(b[i][i].pow(-pow[i])); 86 | if (sign < 0) 87 | det = det.opposite(); 88 | return det; 89 | } 90 | 91 | /** 92 | * Compute the determinant of the Sylvester Matrix. 93 | */ 94 | public static LargeInteger resultant(Polynomial a, Polynomial b, 95 | Variable v) { 96 | int oa = a.getOrder(v); 97 | int ob = b.getOrder(v); 98 | int order = oa + ob; 99 | 100 | LargeInteger[][] rows = new LargeInteger[order][]; 101 | for (int i = 0; i < order; i++) { 102 | rows[i] = new LargeInteger[order]; 103 | for (int j = 0; j < order; j++) { 104 | rows[i][j] = LargeInteger.ZERO; 105 | } 106 | } 107 | for (Term t : a.getTerms()) { 108 | int pow = t.getPower(v); 109 | LargeInteger ca = a.getCoefficient(t); 110 | for (int i = 0; i < ob; i++) { 111 | rows[i + (oa - pow)][i] = ca; 112 | } 113 | } 114 | 115 | for (Term t : b.getTerms()) { 116 | int pow = t.getPower(v); 117 | LargeInteger cb = b.getCoefficient(t); 118 | for (int i = 0; i < oa; i++) { 119 | rows[i + (ob - pow)][i + ob] = cb; 120 | } 121 | } 122 | 123 | return determinantFast(rows); 124 | } 125 | 126 | public static Polynomial gcdEuclidean(Polynomial a, Polynomial b, 127 | Variable v) { 128 | boolean isZeroA = a.equals(ZERO_POLY); 129 | boolean isZeroB = b.equals(ZERO_POLY); 130 | 131 | if (isZeroA) { 132 | if (isZeroB) { 133 | return ZERO_POLY; 134 | } else { 135 | return monic(b, v); 136 | } 137 | } else if (isZeroB) { 138 | return monic(a, v); 139 | } 140 | 141 | throw new RuntimeException("unimplemented"); 142 | } 143 | 144 | public static Polynomial monic(Polynomial in, Variable v) { 145 | LargeInteger coefficient = in.getCoefficient(Term.valueOf(v, in.getOrder(v))); 146 | if (coefficient.equals(1)) 147 | return in; 148 | 149 | return divide(in, coefficient, v); 150 | } 151 | 152 | public static Polynomial divide(Polynomial in, LargeInteger divisor, 153 | Variable v) { 154 | Polynomial out = null; 155 | for (Term t : in.getTerms()) { 156 | Polynomial p = Polynomial.valueOf(in.getCoefficient(t).divide(divisor), t); 157 | out = out == null ? p : out.plus(p); 158 | } 159 | return out == null ? Constant.valueOf(LargeInteger.ZERO) : out; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /shapecpu/src/test/resources/com/grack/shapecpu/creditcard_input.txt: -------------------------------------------------------------------------------- 1 | 1e 35 2e 09 1c 0d 11 3a 05 35 3c 14 3b 2 | 16 08 3e 20 24 10 38 24 18 34 21 17 00 3 | 3c 0b 38 05 24 27 2b 1c 2b 33 17 37 19 4 | 18 1a 23 05 16 3b 1d 36 27 39 36 10 35 5 | 2a 20 36 0a 36 00 2e 22 22 08 23 2b 3e 6 | 2a 30 23 0d 1c 17 39 12 3f 31 21 1b 17 7 | 22 21 2d 19 2e 29 15 26 2f 21 1c 3a 03 8 | 02 2c 1c 28 0c 1e 0c 2e 3c 3a 29 35 30 9 | 2a 3b 35 09 18 29 07 34 23 17 2f 05 1d 10 | 0a 3c 08 1a 1d 33 13 0c 11 3f 32 10 19 11 | 00 2a 2e 02 2a 16 08 22 30 2a 1d 29 1c 12 | 2c 06 1c 32 1b 05 3d 0e 33 3f 09 0f 0d 13 | 24 0d 26 18 3b 35 39 18 0f 03 24 1e 3f 14 | 00 20 1c 24 0a 28 3e 22 16 14 1d 23 32 15 | 04 03 14 32 2f 1b 3f 1c 17 39 09 05 3f 16 | 36 3e 15 2a 0b 21 19 1a 0b 05 18 02 39 17 | 1a 32 0a 32 12 1c 2e 04 08 2c 3f 1f 12 18 | 1c 24 07 34 33 05 1b 0a 11 23 23 19 2d 19 | 24 09 3f 38 03 07 2d 26 1b 1f 20 34 0f 20 | 36 06 2c 12 1a 1e 12 26 3a 06 39 39 2c 21 | 24 01 21 0c 23 0d 15 0a 1d 07 2f 01 03 22 | 0c 22 2e 19 1f 33 15 32 2f 1d 36 1a 0b 23 | 30 22 3a 0a 1a 22 36 06 02 1c 01 0d 3a 24 | 24 2c 3e 3d 0d 21 11 28 3d 17 0f 15 0d 25 | 3a 25 14 37 26 0d 25 18 21 09 0e 06 39 26 | 18 25 0e 19 2c 30 16 3a 35 2c 10 0a 26 27 | 04 0f 2f 09 1f 26 1e 2e 10 1d 20 1a 04 28 | 34 28 3e 1a 1a 26 00 1c 3a 09 24 1b 2a 29 | 25 19 23 38 17 15 0f 29 21 31 26 0f 26 30 | 32 13 0a 35 3e 27 15 1c 37 15 3b 3b 31 31 | 04 28 1f 3b 16 2f 03 18 21 01 34 12 2f 32 | 12 25 22 07 2c 16 36 38 01 08 2e 26 3c 33 | 0e 1c 35 20 3c 29 22 28 12 2f 1e 22 0c 34 | 00 06 18 1a 2e 26 0c 3a 1c 0b 0c 33 08 35 | 33 1f 3f 3c 3d 39 37 35 35 2d 1c 27 16 36 | 0a 1c 27 1b 1a 29 35 22 1b 35 0f 03 2b 37 | 12 05 25 07 18 0d 0d 3c 35 13 0e 1e 39 38 | 12 39 00 29 34 12 0e 0e 3b 24 10 36 3c 39 | 1e 07 2c 31 00 37 02 28 2a 19 2c 3a 08 40 | 16 22 0a 1a 0c 24 3a 10 2a 03 36 2d 36 41 | 09 13 2d 1c 35 1d 25 17 3b 11 24 21 0c 42 | 26 3f 29 0f 08 07 3f 08 0b 3f 11 23 39 43 | 02 20 32 0a 07 2d 3b 3c 2f 2d 2e 38 2f 44 | 22 0b 0e 3d 0a 36 14 28 39 1e 12 38 26 45 | 20 38 34 06 15 1d 26 10 02 0b 2e 26 2c 46 | 32 2c 1e 00 14 12 0a 2e 24 17 14 2f 3c 47 | 11 13 19 1e 39 39 2f 35 35 17 0e 33 18 48 | 34 32 06 26 25 2b 19 06 17 2f 17 25 3f 49 | 28 37 28 3e 3d 27 07 12 3d 25 12 3e 1d 50 | 2e 21 00 2d 1e 2e 02 2c 19 36 04 26 16 51 | 14 2f 3d 1e 33 13 36 2e 22 23 16 3c 1c 52 | 3e 06 36 38 1a 18 06 3c 2e 2f 34 0d 2c 53 | 19 11 03 1c 07 3f 21 3d 2b 37 3c 19 3c 54 | 20 33 3a 24 2f 0b 25 36 25 39 09 21 3d 55 | 3c 28 19 3a 3f 23 01 22 01 23 28 00 1d 56 | 1e 31 06 0d 14 34 0a 38 27 30 36 20 16 57 | 24 3e 01 3f 3f 31 1c 02 3c 19 24 32 30 58 | 2e 34 34 0c 34 3c 1c 12 1a 1f 02 37 1c 59 | 35 1d 1f 22 1b 31 2f 2d 03 0d 26 31 0e 60 | 2e 3e 3f 30 37 01 13 3e 21 3f 2f 13 0f 61 | 00 3f 09 24 0d 17 11 1a 2f 2b 2a 26 31 62 | 3c 11 1a 23 22 34 16 30 35 32 0c 1c 16 63 | 02 3f 16 2c 04 28 0d 28 08 1f 0e 2a 2c 64 | 22 10 28 28 34 06 1c 1e 2c 0d 2a 29 00 65 | 05 1b 3b 26 27 13 07 25 0b 3d 08 05 28 66 | 2a 11 37 20 05 0f 15 0e 11 03 0d 29 19 67 | 08 36 14 2d 1d 09 03 26 3f 1d 1e 00 05 68 | 24 15 14 37 02 3c 02 2a 09 36 08 0e 16 69 | 04 34 08 1d 14 22 31 10 22 25 04 2e 16 70 | 32 1a 24 2a 0e 2c 10 10 20 2f 36 07 30 71 | 31 1d 1f 34 21 3b 21 31 05 29 02 3b 1c 72 | 1c 34 3e 0f 31 31 29 22 07 17 3b 05 25 73 | 14 2c 00 2a 08 1c 0a 0c 2c 07 2c 0f 3c 74 | 0a 1d 2c 31 12 39 1f 24 0f 2f 2c 28 2d 75 | 36 28 01 15 22 2d 2f 14 37 2d 14 11 01 76 | 2c 33 3d 29 28 03 37 0a 13 35 14 1f 07 77 | 2c 0a 3c 20 01 27 35 2a 03 35 1c 05 09 78 | 12 23 2e 16 07 25 17 34 19 19 10 25 1f 79 | 2c 38 31 32 31 25 05 20 1f 35 32 0d 39 80 | 18 27 1f 24 21 21 11 3a 37 35 34 3d 37 81 | 12 00 12 2f 23 03 0d 0a 39 3b 38 17 03 82 | 0f 00 0f 02 0a 21 19 06 1b 1f 37 3d 17 83 | 10 1e 0a 04 0e 28 1a 24 0a 11 1e 21 16 84 | 1d 2b 12 31 14 25 23 22 03 37 38 34 05 85 | 19 2c 15 1f 06 35 15 22 25 01 2a 37 05 86 | 3f 01 3f 07 34 01 2d 02 2f 3f 06 09 29 87 | 33 0a 0c 14 0f 39 2b 1c 33 19 24 13 1b 88 | 01 15 20 1a 09 37 1b 34 19 05 08 21 21 89 | 3d 1c 15 2e 1b 0b 39 0a 05 1b 10 0d 19 90 | 0b 19 19 28 07 0b 29 10 25 03 08 15 2d 91 | 2a 19 09 0a 38 1f 15 32 15 1b 2d 27 11 92 | 31 02 25 00 04 1d 0d 38 23 15 34 07 3f 93 | 27 39 39 32 2a 03 39 02 21 39 27 35 07 94 | 26 12 32 3d 04 39 1b 36 25 1b 21 31 2f 95 | 04 36 2a 0e 30 24 04 30 06 17 1c 3d 3c 96 | 06 1b 27 10 09 2f 21 15 0f 33 1a 25 14 97 | 1a 17 3e 39 34 28 2e 14 0d 12 38 1e 00 98 | 11 19 0c 2a 12 3b 21 3c 3e 39 22 2c 3e 99 | 2c 1b 0f 11 31 1c 3b 28 32 28 35 02 36 100 | 00 24 26 01 3e 3f 27 28 0f 09 37 3b 0b 101 | 0a 28 05 3e 1c 39 29 10 3a 2c 19 3e 16 102 | 0a 2c 04 32 2c 0c 2c 30 3c 0d 29 27 2c 103 | 08 18 3c 38 0a 3c 1a 2e 38 39 21 09 06 104 | 00 16 02 08 3e 0c 2e 2c 34 07 3b 3f 18 105 | 0c 0c 06 22 22 08 30 14 18 09 29 0b 00 106 | 3f 1b 3a 38 30 39 2b 3c 2e 2d 15 11 3e 107 | 33 3e 09 26 30 18 14 14 06 2b 31 17 20 108 | 24 36 39 3e 3e 3c 32 06 04 23 07 0b 1c 109 | 19 2a 24 2d 3c 3c 2e 3c 12 25 37 21 0e 110 | 37 3d 35 04 34 18 2c 1a 1a 23 0f 07 32 111 | 3e 06 20 10 00 38 14 2a 00 0f 2f 1d 1c 112 | 13 11 0a 30 24 32 16 22 1a 01 39 17 3c 113 | 08 31 25 22 20 1e 16 02 36 31 13 31 14 114 | 13 08 3b 30 34 16 02 16 00 33 3f 3b 1e 115 | 32 3a 2a 26 30 38 3c 1e 02 27 01 07 28 116 | 3a 09 30 36 20 3c 32 10 2c 37 0b 03 3a 117 | 19 02 0c 32 3c 32 06 0e 0a 31 2f 23 32 118 | 38 11 2d 06 3e 1c 08 3a 02 3d 37 0f 1c 119 | 35 1c 2a 1c 16 0c 22 02 14 3d 1b 1b 2c 120 | 1a 07 1b 04 22 3a 20 04 22 3d 37 3d 20 121 | 30 24 30 32 12 3c 02 20 02 05 21 25 24 122 | 3e 08 28 0c 1a 1c 32 18 1a 11 35 15 28 123 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/Main.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.docopt.Docopt; 10 | 11 | import com.google.common.base.Charsets; 12 | import com.google.common.io.Files; 13 | import com.grack.hidecpu.assembler.Compiler; 14 | import com.grack.hidecpu.assembler.Parser; 15 | import com.grack.hidecpu.assembler.Program; 16 | import com.grack.homomorphic.light.LightBitFactory; 17 | import com.grack.homomorphic.light.StandardStateFactory; 18 | import com.grack.homomorphic.light.WordArrayDumper; 19 | import com.grack.homomorphic.ops.State; 20 | import com.grack.homomorphic.ops.Word; 21 | 22 | public class Main { 23 | public static void main(String[] args) throws IOException { 24 | Map parsed = new Docopt( 25 | Main.class.getResourceAsStream("/command-line.txt"), 26 | Charsets.US_ASCII).withExit(true).withHelp(true).parse(args); 27 | 28 | if ((Boolean) parsed.get("run")) { 29 | int ticks = parsed.get("--ticks") == null ? -1 : Integer 30 | .parseInt((String) parsed.get("--ticks")); 31 | run((String) parsed.get(""), ticks, 32 | (Boolean) parsed.get("--debug")); 33 | return; 34 | } 35 | 36 | if ((Boolean) parsed.get("assemble")) { 37 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 38 | new File((String) parsed.get(""))) 39 | : System.out; 40 | assemble((String) parsed.get(""), out); 41 | return; 42 | } 43 | 44 | if ((Boolean) parsed.get("pretty")) { 45 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 46 | new File((String) parsed.get(""))) 47 | : System.out; 48 | pretty((String) parsed.get(""), 49 | (Boolean) parsed.get("--process-labels"), out); 50 | return; 51 | } 52 | } 53 | 54 | private static void run(String file, int ticks, boolean debug) 55 | throws IOException { 56 | if (ticks == -1) 57 | System.err.println("Running " + file + " until complete"); 58 | else 59 | System.err 60 | .println("Running " + file + " for " + ticks + " tick(s)"); 61 | 62 | Map initialState = new HashMap<>(); 63 | 64 | if (file.endsWith(".asm")) { 65 | Parser parser = new Parser(Files.asCharSource(new File(file), 66 | Charsets.UTF_8)); 67 | Program program = parser.parse(); 68 | Compiler compiler = new Compiler(); 69 | compiler.compile(program); 70 | 71 | initialState.put("pc", 0); 72 | initialState.put("memory", program.getProgram()); 73 | } else if (file.endsWith(".obj")) { 74 | 75 | } else { 76 | System.err.println("Only .obj and .asm files may be run"); 77 | System.exit(1); 78 | } 79 | 80 | CPU cpu = new CPU(); 81 | LightBitFactory factory = new LightBitFactory(); 82 | StandardStateFactory stateFactory = new StandardStateFactory(factory, 83 | initialState, debug); 84 | cpu.initialize(factory, stateFactory); 85 | 86 | State state = stateFactory.createState(); 87 | 88 | int actualTicks = 0; 89 | long lastPc = -1; 90 | for (int i = 0; ticks == -1 ? true : i < ticks; i++) { 91 | actualTicks++; 92 | cpu.tick(state); 93 | long pc = factory.extract(state.getWordRegister("pc")); 94 | if (ticks == -1 && pc == lastPc) { 95 | System.err 96 | .println("Complete after " + actualTicks + " tick(s)"); 97 | break; 98 | } 99 | lastPc = pc; 100 | } 101 | 102 | Word[] memory = state.getWordArrayRegister("memory"); 103 | 104 | WordArrayDumper.dump(factory, memory); 105 | 106 | System.err.println("XOR count = " + factory.getXorCount()); 107 | System.err.println("AND count = " + factory.getAndCount()); 108 | } 109 | 110 | private static void pretty(String file, boolean processLabels, 111 | PrintStream out) throws IOException { 112 | System.err.println("Pretty-printing " + file); 113 | 114 | Parser parser = new Parser(Files.asCharSource(new File(file), 115 | Charsets.UTF_8)); 116 | Program program = parser.parse(); 117 | 118 | if (processLabels) { 119 | Compiler compiler = new Compiler(); 120 | compiler.compile(program); 121 | } 122 | 123 | program.getLines().forEach((line) -> { 124 | out.println(line); 125 | }); 126 | } 127 | 128 | private static void assemble(String file, PrintStream out) 129 | throws IOException { 130 | System.err.println("Assembling " + file); 131 | 132 | Parser parser = new Parser(Files.asCharSource(new File(file), 133 | Charsets.UTF_8)); 134 | Program program = parser.parse(); 135 | 136 | Compiler compiler = new Compiler(); 137 | compiler.compile(program); 138 | 139 | program.getLines().forEach((line) -> { 140 | for (int i : line.assemble()) 141 | out.println(encode(8, i)); 142 | }); 143 | } 144 | 145 | private static String encode(int bits, int value) { 146 | StringBuilder builder = new StringBuilder(); 147 | for (int i = 0; i < bits; i++) { 148 | int out = (int) (Math.random() * 64); 149 | if ((value & (1 << i)) == 0) { 150 | out = out & ~1; 151 | } else { 152 | out = out | 1; 153 | } 154 | 155 | builder.append(String.format("%02x", out)); 156 | if (i != bits - 1) 157 | builder.append(" "); 158 | } 159 | 160 | return builder.toString(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/Main.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.docopt.Docopt; 10 | 11 | import com.google.common.base.Charsets; 12 | import com.google.common.io.Files; 13 | import com.grack.hidecpu2.assembler.Compiler; 14 | import com.grack.hidecpu2.assembler.Parser; 15 | import com.grack.hidecpu2.assembler.Program; 16 | import com.grack.homomorphic.light.LightBitFactory; 17 | import com.grack.homomorphic.light.StandardStateFactory; 18 | import com.grack.homomorphic.light.WordArrayDumper; 19 | import com.grack.homomorphic.ops.State; 20 | import com.grack.homomorphic.ops.Word; 21 | 22 | public class Main { 23 | public static void main(String[] args) throws IOException { 24 | Map parsed = new Docopt( 25 | Main.class.getResourceAsStream("/command-line.txt"), 26 | Charsets.US_ASCII).withExit(true).withHelp(true).parse(args); 27 | 28 | if ((Boolean) parsed.get("run")) { 29 | int ticks = parsed.get("--ticks") == null ? -1 : Integer 30 | .parseInt((String) parsed.get("--ticks")); 31 | run((String) parsed.get(""), ticks, 32 | (Boolean) parsed.get("--debug")); 33 | return; 34 | } 35 | 36 | if ((Boolean) parsed.get("assemble")) { 37 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 38 | new File((String) parsed.get(""))) 39 | : System.out; 40 | assemble((String) parsed.get(""), out); 41 | return; 42 | } 43 | 44 | if ((Boolean) parsed.get("pretty")) { 45 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 46 | new File((String) parsed.get(""))) 47 | : System.out; 48 | pretty((String) parsed.get(""), 49 | (Boolean) parsed.get("--process-labels"), out); 50 | return; 51 | } 52 | } 53 | 54 | private static void run(String file, int ticks, boolean debug) 55 | throws IOException { 56 | if (ticks == -1) 57 | System.err.println("Running " + file + " until complete"); 58 | else 59 | System.err 60 | .println("Running " + file + " for " + ticks + " tick(s)"); 61 | 62 | Map initialState = new HashMap<>(); 63 | 64 | if (file.endsWith(".asm")) { 65 | Parser parser = new Parser(Files.asCharSource(new File(file), 66 | Charsets.UTF_8)); 67 | Program program = parser.parse(); 68 | Compiler compiler = new Compiler(); 69 | compiler.compile(program); 70 | 71 | initialState.put(CPU.PC, 0); 72 | initialState.put(CPU.MEMORY_CODE, program.getProgram("code")); 73 | initialState.put(CPU.MEMORY_DATA, program.getProgram("data")); 74 | } else if (file.endsWith(".obj")) { 75 | 76 | } else { 77 | System.err.println("Only .obj and .asm files may be run"); 78 | System.exit(1); 79 | } 80 | 81 | CPU cpu = new CPU(); 82 | LightBitFactory factory = new LightBitFactory(); 83 | StandardStateFactory stateFactory = new StandardStateFactory(factory, 84 | initialState, debug); 85 | cpu.initialize(factory, stateFactory); 86 | 87 | State state = stateFactory.createState(); 88 | 89 | int actualTicks = 0; 90 | long lastPc = -1; 91 | for (int i = 0; ticks == -1 ? true : i < ticks; i++) { 92 | actualTicks++; 93 | cpu.tick(state); 94 | long pc = factory.extract(state.getWordRegister("pc")); 95 | if (ticks == -1 && pc == lastPc) { 96 | System.err 97 | .println("Complete after " + actualTicks + " tick(s)"); 98 | break; 99 | } 100 | lastPc = pc; 101 | } 102 | 103 | Word[] memory = state.getWordArrayRegister("memory"); 104 | 105 | WordArrayDumper.dump(factory, memory); 106 | 107 | System.err.println("XOR count = " + factory.getXorCount()); 108 | System.err.println("AND count = " + factory.getAndCount()); 109 | } 110 | 111 | private static void pretty(String file, boolean processLabels, 112 | PrintStream out) throws IOException { 113 | System.err.println("Pretty-printing " + file); 114 | 115 | Parser parser = new Parser(Files.asCharSource(new File(file), 116 | Charsets.UTF_8)); 117 | Program program = parser.parse(); 118 | 119 | if (processLabels) { 120 | Compiler compiler = new Compiler(); 121 | compiler.compile(program); 122 | } 123 | 124 | program.getLines().forEach((line) -> { 125 | out.println(line); 126 | }); 127 | } 128 | 129 | private static void assemble(String file, PrintStream out) 130 | throws IOException { 131 | System.err.println("Assembling " + file); 132 | 133 | Parser parser = new Parser(Files.asCharSource(new File(file), 134 | Charsets.UTF_8)); 135 | Program program = parser.parse(); 136 | 137 | Compiler compiler = new Compiler(); 138 | compiler.compile(program); 139 | 140 | program.getLines().forEach((line) -> { 141 | for (int i : line.assemble()) 142 | out.println(encode(8, i)); 143 | }); 144 | } 145 | 146 | private static String encode(int bits, int value) { 147 | StringBuilder builder = new StringBuilder(); 148 | for (int i = 0; i < bits; i++) { 149 | int out = (int) (Math.random() * 64); 150 | if ((value & (1 << i)) == 0) { 151 | out = out & ~1; 152 | } else { 153 | out = out | 1; 154 | } 155 | 156 | builder.append(String.format("%02x", out)); 157 | if (i != bits - 1) 158 | builder.append(" "); 159 | } 160 | 161 | return builder.toString(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/Main.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.docopt.Docopt; 10 | 11 | import com.google.common.base.Charsets; 12 | import com.google.common.io.Files; 13 | import com.grack.homomorphic.light.LightBitFactory; 14 | import com.grack.homomorphic.light.StandardStateFactory; 15 | import com.grack.homomorphic.light.WordArrayDumper; 16 | import com.grack.homomorphic.ops.State; 17 | import com.grack.homomorphic.ops.Word; 18 | import com.grack.shapecpu.assembler.Compiler; 19 | import com.grack.shapecpu.assembler.Parser; 20 | import com.grack.shapecpu.assembler.Program; 21 | 22 | public class Main { 23 | public static void main(String[] args) throws IOException { 24 | Map parsed = new Docopt( 25 | Main.class.getResourceAsStream("/command-line.txt"), 26 | Charsets.US_ASCII).withExit(true).withHelp(true).parse(args); 27 | 28 | if ((Boolean) parsed.get("run")) { 29 | int ticks = parsed.get("--ticks") == null ? -1 : Integer 30 | .parseInt((String) parsed.get("--ticks")); 31 | run((String) parsed.get(""), ticks, 32 | (Boolean) parsed.get("--debug")); 33 | return; 34 | } 35 | 36 | if ((Boolean) parsed.get("assemble")) { 37 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 38 | new File((String) parsed.get(""))) 39 | : System.out; 40 | assemble((String) parsed.get(""), out); 41 | return; 42 | } 43 | 44 | if ((Boolean) parsed.get("pretty")) { 45 | PrintStream out = (Boolean) parsed.get("-o") ? new PrintStream( 46 | new File((String) parsed.get(""))) 47 | : System.out; 48 | pretty((String) parsed.get(""), 49 | (Boolean) parsed.get("--process-labels"), out); 50 | return; 51 | } 52 | } 53 | 54 | private static void run(String file, int ticks, boolean debug) 55 | throws IOException { 56 | if (ticks == -1) 57 | System.err.println("Running " + file + " until complete"); 58 | else 59 | System.err.println("Running " + file + " for " + ticks + " tick(s)"); 60 | 61 | Map initialState = new HashMap<>(); 62 | 63 | if (file.endsWith(".asm")) { 64 | Parser parser = new Parser(Files.asCharSource(new File(file), 65 | Charsets.UTF_8)); 66 | Program program = parser.parse(); 67 | Compiler compiler = new Compiler(); 68 | compiler.compile(program); 69 | 70 | initialState.put("ac", program.getInitAc().getValue()); 71 | initialState.put("pc", program.getInitPc().getValue()); 72 | initialState.put("memory", program.getProgram()); 73 | } else if (file.endsWith(".obj")) { 74 | 75 | } else { 76 | System.err.println("Only .obj and .asm files may be run"); 77 | System.exit(1); 78 | } 79 | 80 | CPU cpu = new CPU(); 81 | LightBitFactory factory = new LightBitFactory(); 82 | StandardStateFactory stateFactory = new StandardStateFactory(factory, 83 | initialState, debug); 84 | cpu.initialize(factory, stateFactory); 85 | 86 | State state = stateFactory.createState(); 87 | 88 | int actualTicks = 0; 89 | long lastPc = -1; 90 | for (int i = 0; ticks == -1 ? true : i < ticks; i++) { 91 | actualTicks++; 92 | cpu.tick(state); 93 | long pc = factory.extract(state.getWordRegister("pc")); 94 | if (ticks == -1 && pc == lastPc) { 95 | System.err.println("Complete after " + actualTicks + " tick(s)"); 96 | break; 97 | } 98 | lastPc = pc; 99 | } 100 | 101 | Word[] memory = state.getWordArrayRegister("memory"); 102 | WordArrayDumper.dump(factory, memory); 103 | 104 | System.err.println("XOR count = " + factory.getXorCount()); 105 | System.err.println("AND count = " + factory.getAndCount()); 106 | } 107 | 108 | private static void pretty(String file, boolean processLabels, 109 | PrintStream out) throws IOException { 110 | System.err.println("Pretty-printing " + file); 111 | 112 | Parser parser = new Parser(Files.asCharSource(new File(file), 113 | Charsets.UTF_8)); 114 | Program program = parser.parse(); 115 | 116 | if (processLabels) { 117 | Compiler compiler = new Compiler(); 118 | compiler.compile(program); 119 | } 120 | 121 | out.println("INITAC " + program.getInitAc()); 122 | out.println("INITPC " + program.getInitPc()); 123 | program.getLines().forEach((line) -> { 124 | out.println(line); 125 | }); 126 | } 127 | 128 | private static void assemble(String file, PrintStream out) 129 | throws IOException { 130 | System.err.println("Assembling " + file); 131 | 132 | Parser parser = new Parser(Files.asCharSource(new File(file), 133 | Charsets.UTF_8)); 134 | Program program = parser.parse(); 135 | 136 | Compiler compiler = new Compiler(); 137 | compiler.compile(program); 138 | 139 | out.println("INITAC " 140 | + encode(13, (int) program.getInitAc().getValue())); 141 | out.println("INITPC " + encode(8, (int) program.getInitPc().getValue())); 142 | program.getLines().forEach((line) -> { 143 | out.println(encode(13, line.assemble())); 144 | }); 145 | } 146 | 147 | private static String encode(int bits, int value) { 148 | StringBuilder builder = new StringBuilder(); 149 | for (int i = 0; i < bits; i++) { 150 | int out = (int) (Math.random() * 64); 151 | if ((value & (1 << i)) == 0) { 152 | out = out & ~1; 153 | } else { 154 | out = out | 1; 155 | } 156 | 157 | builder.append(String.format("%02x", out)); 158 | if (i != bits - 1) 159 | builder.append(" "); 160 | } 161 | 162 | return builder.toString(); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /shapecpu/src/test/java/com/grack/shapecpu/SortSampleTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.OutputStreamWriter; 10 | import java.io.Writer; 11 | import java.util.Map; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | import com.google.common.base.Charsets; 17 | import com.google.common.collect.ImmutableMap; 18 | import com.google.common.io.Resources; 19 | import com.grack.homomorphic.graph.Graph; 20 | import com.grack.homomorphic.light.LightBitFactory; 21 | import com.grack.homomorphic.light.StandardStateFactory; 22 | import com.grack.homomorphic.logging.LoggingBitFactory; 23 | import com.grack.homomorphic.logging.LoggingStateFactory; 24 | import com.grack.homomorphic.ops.State; 25 | import com.grack.homomorphic.ops.StateFactory; 26 | import com.grack.homomorphic.ops.Word; 27 | 28 | public class SortSampleTest { 29 | private int[] memory; 30 | private int[] output; 31 | private Map initialState; 32 | 33 | @Before 34 | public void setup() throws IOException { 35 | String mem = Resources.toString( 36 | getClass().getResource("sort_input.txt"), Charsets.UTF_8); 37 | String[] memoryContents = mem.trim().split("\n"); 38 | // debug("memory size:", memoryContents.length); 39 | memory = new int[256]; 40 | 41 | for (int i = 0; i < memoryContents.length; i++) { 42 | String line = memoryContents[i]; 43 | String[] bytes = line.split(" "); 44 | int value = 0; 45 | for (int j = 0; j < 13; j++) { 46 | value |= (Integer.valueOf(bytes[j], 16) & 1) << j; 47 | } 48 | 49 | // System.out.println(i + " " + String.format("%13s", 50 | // Integer.toString(value, 2)) 51 | // .replace(" ", "0")); 52 | memory[i] = value; 53 | } 54 | 55 | String out = Resources 56 | .toString(getClass().getResource("sort_output.txt"), 57 | Charsets.UTF_8); 58 | String[] outputContents = out.trim().split("\n"); 59 | 60 | output = new int[outputContents.length]; 61 | 62 | for (int i = 0; i < outputContents.length; i++) { 63 | String[] bits = outputContents[i].trim().split(" "); 64 | output[i] = Integer.valueOf(bits[1]); 65 | } 66 | 67 | initialState = ImmutableMap.of("memory", memory, "pc", 10); 68 | } 69 | 70 | @Test 71 | public void cpuTurnsOn() { 72 | LightBitFactory factory = new LightBitFactory(); 73 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 74 | CPU cpu = new CPU(); 75 | cpu.initialize(factory, stateFactory); 76 | State state = stateFactory.createState(); 77 | cpu.tick(state); 78 | } 79 | 80 | @Test 81 | public void cpuLogging() throws FileNotFoundException, IOException { 82 | LoggingBitFactory factory = new LoggingBitFactory(); 83 | LoggingStateFactory stateFactory = new LoggingStateFactory(factory); 84 | CPU cpu = new CPU(); 85 | cpu.initialize(factory, stateFactory); 86 | State state = stateFactory.createState(); 87 | cpu.tick(state); 88 | 89 | // Bit bit = state.getBitRegister("alu_carry"); 90 | // System.out.println(((LoggingBit) bit.nativeBit()).describe()); 91 | 92 | Graph graph = factory.toGraph(); 93 | graph.optimize(); 94 | 95 | try (Writer w = new OutputStreamWriter(new FileOutputStream( 96 | "/tmp/output.txt"))) { 97 | graph.toC(w); 98 | } 99 | } 100 | 101 | @Test 102 | public void cpuTicksTwice() { 103 | LightBitFactory factory = new LightBitFactory(); 104 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 105 | CPU cpu = new CPU(); 106 | cpu.initialize(factory, stateFactory); 107 | State state = stateFactory.createState(); 108 | cpu.tick(state); 109 | cpu.tick(state); 110 | } 111 | 112 | @Test 113 | public void cpuTicksThrice() { 114 | LightBitFactory factory = new LightBitFactory(); 115 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 116 | CPU cpu = new CPU(); 117 | cpu.initialize(factory, stateFactory); 118 | State state = stateFactory.createState(); 119 | cpu.tick(state); 120 | cpu.tick(state); 121 | cpu.tick(state); 122 | } 123 | 124 | @Test 125 | public void cpuTicks300() { 126 | LightBitFactory factory = new LightBitFactory(); 127 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 128 | CPU cpu = new CPU(); 129 | cpu.initialize(factory, stateFactory); 130 | State state = stateFactory.createState(); 131 | for (int i = 0; i < 300; i++) { 132 | cpu.tick(state); 133 | } 134 | 135 | System.out.println("XOR count = " + factory.getXorCount()); 136 | System.out.println("AND count = " + factory.getAndCount()); 137 | } 138 | 139 | @Test 140 | public void cpuTicksUntilDone() { 141 | LightBitFactory factory = new LightBitFactory(); 142 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 143 | CPU cpu = new CPU(); 144 | cpu.initialize(factory, stateFactory); 145 | State state = stateFactory.createState(); 146 | 147 | long lastPC = -1; 148 | for (int i = 0; i < 20000; i++) { 149 | long pc = factory.extract(state.getWordRegister("pc")); 150 | if (pc == lastPC) { 151 | // Success 152 | System.out.println("Total ticks: " + i); 153 | dumpMemory(factory, state); 154 | System.out.println("All memory locations match."); 155 | return; 156 | } 157 | lastPC = pc; 158 | 159 | cpu.tick(state); 160 | } 161 | 162 | dumpMemory(factory, state); 163 | fail(); 164 | } 165 | 166 | private void dumpMemory(LightBitFactory factory, State state) { 167 | Word[] memory = state.getWordArrayRegister("memory"); 168 | for (int j = 0; j < output.length; j++) { 169 | long mem = factory.extract(memory[j]) & 0xff; 170 | assertEquals((long)output[j], mem); 171 | // System.out.println(String.format("%3d: %s %5d", j, 172 | // memory[j].toString(), mem)); 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /shapecpu/src/test/java/com/grack/shapecpu/CreditCardSampleTest.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.OutputStreamWriter; 10 | import java.io.Writer; 11 | import java.util.Map; 12 | 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | import com.google.common.base.Charsets; 17 | import com.google.common.collect.ImmutableMap; 18 | import com.google.common.io.Resources; 19 | import com.grack.homomorphic.graph.Graph; 20 | import com.grack.homomorphic.light.LightBitFactory; 21 | import com.grack.homomorphic.light.StandardStateFactory; 22 | import com.grack.homomorphic.logging.LoggingBitFactory; 23 | import com.grack.homomorphic.logging.LoggingStateFactory; 24 | import com.grack.homomorphic.ops.State; 25 | import com.grack.homomorphic.ops.StateFactory; 26 | import com.grack.homomorphic.ops.Word; 27 | 28 | public class CreditCardSampleTest { 29 | private int[] memory; 30 | private int[] output; 31 | private Map initialState; 32 | 33 | @Before 34 | public void setup() throws IOException { 35 | String mem = Resources.toString( 36 | getClass().getResource("creditcard_input.txt"), Charsets.UTF_8); 37 | String[] memoryContents = mem.trim().split("\n"); 38 | // debug("memory size:", memoryContents.length); 39 | memory = new int[256]; 40 | 41 | for (int i = 0; i < memoryContents.length; i++) { 42 | String line = memoryContents[i]; 43 | String[] bytes = line.split(" "); 44 | int value = 0; 45 | for (int j = 0; j < 13; j++) { 46 | value |= (Integer.valueOf(bytes[j], 16) & 1) << j; 47 | } 48 | 49 | // System.out.println(i + " " + String.format("%13s", 50 | // Integer.toString(value, 2)) 51 | // .replace(" ", "0")); 52 | memory[i] = value; 53 | } 54 | 55 | String out = Resources 56 | .toString(getClass().getResource("creditcard_output.txt"), 57 | Charsets.UTF_8); 58 | String[] outputContents = out.trim().split("\n"); 59 | 60 | output = new int[outputContents.length]; 61 | 62 | for (int i = 0; i < outputContents.length; i++) { 63 | String[] bits = outputContents[i].trim().split(" "); 64 | output[i] = Integer.valueOf(bits[1]); 65 | } 66 | 67 | initialState = ImmutableMap.of("memory", memory); 68 | } 69 | 70 | @Test 71 | public void cpuTurnsOn() { 72 | LightBitFactory factory = new LightBitFactory(); 73 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 74 | CPU cpu = new CPU(); 75 | cpu.initialize(factory, stateFactory); 76 | State state = stateFactory.createState(); 77 | cpu.tick(state); 78 | } 79 | 80 | @Test 81 | public void cpuLogging() throws FileNotFoundException, IOException { 82 | LoggingBitFactory factory = new LoggingBitFactory(); 83 | LoggingStateFactory stateFactory = new LoggingStateFactory(factory); 84 | CPU cpu = new CPU(); 85 | cpu.initialize(factory, stateFactory); 86 | State state = stateFactory.createState(); 87 | cpu.tick(state); 88 | 89 | // Bit bit = state.getBitRegister("alu_carry"); 90 | // System.out.println(((LoggingBit) bit.nativeBit()).describe()); 91 | 92 | Graph graph = factory.toGraph(); 93 | graph.optimize(); 94 | 95 | try (Writer w = new OutputStreamWriter(new FileOutputStream( 96 | "/tmp/output.txt"))) { 97 | graph.toC(w); 98 | } 99 | } 100 | 101 | @Test 102 | public void cpuTicksTwice() { 103 | LightBitFactory factory = new LightBitFactory(); 104 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 105 | CPU cpu = new CPU(); 106 | cpu.initialize(factory, stateFactory); 107 | State state = stateFactory.createState(); 108 | cpu.tick(state); 109 | cpu.tick(state); 110 | } 111 | 112 | @Test 113 | public void cpuTicksThrice() { 114 | LightBitFactory factory = new LightBitFactory(); 115 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 116 | CPU cpu = new CPU(); 117 | cpu.initialize(factory, stateFactory); 118 | State state = stateFactory.createState(); 119 | cpu.tick(state); 120 | cpu.tick(state); 121 | cpu.tick(state); 122 | } 123 | 124 | @Test 125 | public void cpuTicks300() { 126 | LightBitFactory factory = new LightBitFactory(); 127 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 128 | CPU cpu = new CPU(); 129 | cpu.initialize(factory, stateFactory); 130 | State state = stateFactory.createState(); 131 | for (int i = 0; i < 300; i++) { 132 | cpu.tick(state); 133 | } 134 | } 135 | 136 | @Test 137 | public void cpuTicksUntilDone() { 138 | LightBitFactory factory = new LightBitFactory(); 139 | StateFactory stateFactory = new StandardStateFactory(factory, initialState, false); 140 | CPU cpu = new CPU(); 141 | cpu.initialize(factory, stateFactory); 142 | State state = stateFactory.createState(); 143 | 144 | long lastPC = -1; 145 | for (int i = 0; i < 20000; i++) { 146 | long pc = factory.extract(state.getWordRegister("pc")); 147 | if (pc == lastPC) { 148 | // Success 149 | System.out.println("Total ticks: " + i); 150 | dumpMemory(factory, state); 151 | System.out.println("All memory locations match."); 152 | System.out.println("XOR count = " + factory.getXorCount()); 153 | System.out.println("AND count = " + factory.getAndCount()); 154 | return; 155 | } 156 | lastPC = pc; 157 | 158 | cpu.tick(state); 159 | } 160 | 161 | dumpMemory(factory, state); 162 | fail(); 163 | } 164 | 165 | private void dumpMemory(LightBitFactory factory, State state) { 166 | Word[] memory = state.getWordArrayRegister("memory"); 167 | for (int j = 0; j < output.length; j++) { 168 | long mem = factory.extract(memory[j]) & 0xff; 169 | assertEquals((long)output[j], mem); 170 | // System.out.println(String.format("%3d: %s %5d", j, 171 | // memory[j].toString(), mem)); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /hidecpu/src/main/java/com/grack/hidecpu/assembler/Parser.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu.assembler; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.Arrays; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | 9 | import com.google.common.base.CharMatcher; 10 | import com.google.common.base.Splitter; 11 | import com.google.common.io.CharSource; 12 | 13 | public class Parser { 14 | private CharSource source; 15 | private Splitter OPCODE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE) 16 | .trimResults().omitEmptyStrings().limit(2); 17 | private Splitter PARAM_SPLITTER = Splitter.on(',').trimResults() 18 | .omitEmptyStrings(); 19 | 20 | public Parser(CharSource source) { 21 | this.source = source; 22 | } 23 | 24 | public Program parse() throws IOException { 25 | Program program = new Program(); 26 | List lines = program.getLines(); 27 | source.readLines().forEach((line) -> { 28 | lines.addAll(parseLine(line)); 29 | }); 30 | 31 | return program; 32 | } 33 | 34 | private List parseLine(String line) { 35 | try { 36 | if (line.indexOf('#') != -1) 37 | line = line.substring(0, line.indexOf('#')); 38 | 39 | line = line.trim(); 40 | if (line.isEmpty()) 41 | return Arrays.asList(new Line(null, null, null)); 42 | 43 | String label = null; 44 | if (line.matches("^[a-zA-Z0-9_]+:$")) { 45 | label = line.substring(0, line.indexOf(':')); 46 | line = line.substring(line.indexOf(':') + 1); 47 | } 48 | 49 | line = line.trim(); 50 | if (line.isEmpty()) 51 | return Arrays.asList(new Line(label)); 52 | 53 | Iterator pieces = OPCODE_SPLITTER.split(line).iterator(); 54 | 55 | String opcode = pieces.next().toLowerCase(); 56 | String params = pieces.hasNext() ? pieces.next() : null; 57 | 58 | Opcode op; 59 | OpSource src = null; 60 | OpTarget target = null; 61 | Value value = null; 62 | 63 | switch (opcode) { 64 | case "data": { 65 | List lines = new ArrayList<>(); 66 | for (String data : PARAM_SPLITTER.split(params)) { 67 | lines.add(new Line(parseValue(data))); 68 | } 69 | return lines; 70 | } 71 | case "mov": { 72 | Iterator it = PARAM_SPLITTER.split(params).iterator(); 73 | String left = it.next(); 74 | String right = it.next(); 75 | if (left.startsWith("[")) { 76 | op = Opcode.STORE; 77 | target = OpTarget.valueOf(right.toUpperCase()); 78 | src = parseSource(left); 79 | value = parseSourceValue(left); 80 | } else { 81 | if (right.startsWith("rol")) { 82 | op = Opcode.ROL; 83 | right = right.substring(3).trim(); 84 | } else if (right.startsWith("ror")) { 85 | op = Opcode.ROR; 86 | right = right.substring(3).trim(); 87 | } else if (right.startsWith("not")) { 88 | op = Opcode.NOT; 89 | right = right.substring(3).trim(); 90 | } else { 91 | op = Opcode.LOAD; 92 | } 93 | target = OpTarget.valueOf(left.toUpperCase()); 94 | src = parseSource(right); 95 | value = parseSourceValue(right); 96 | } 97 | break; 98 | } 99 | case "jump": 100 | op = Opcode.JUMP; 101 | src = parseSource(params); 102 | value = parseSourceValue(params); 103 | break; 104 | case "clc": 105 | op = Opcode.CARRY; 106 | value = new Value(0); 107 | break; 108 | case "sec": 109 | op = Opcode.CARRY; 110 | value = new Value(1); 111 | break; 112 | case "blt": 113 | case "blte": 114 | case "beq": 115 | case "bca": 116 | case "bgt": 117 | case "bgte": 118 | case "bne": 119 | case "bnc": 120 | op = Opcode.BRA; 121 | BranchType branchType = BranchType.valueOf(opcode.substring(1) 122 | .toUpperCase()); 123 | return Arrays.asList(new Line(label, Opcode.BRA, branchType, 124 | parseValue(params))); 125 | case "loop": 126 | case "cmp": 127 | case "add": 128 | case "sub": 129 | case "and": 130 | case "xor": 131 | case "or": { 132 | op = Opcode.valueOf(opcode.toUpperCase()); 133 | Iterator it = PARAM_SPLITTER.split(params).iterator(); 134 | String left = it.next(); 135 | String right = it.next(); 136 | target = OpTarget.valueOf(left.toUpperCase()); 137 | src = parseSource(right); 138 | value = parseSourceValue(right); 139 | break; 140 | } 141 | case "halt": 142 | // TODO: This could be cleaner 143 | return Arrays.asList(new Line(null, Opcode.JUMP, 144 | OpSource.CONSTANT, null, new Value("pc"))); 145 | default: 146 | throw new RuntimeException("Invalid opcode: " + opcode); 147 | } 148 | 149 | Line result = new Line(label, op, src, target, value); 150 | return Arrays.asList(result); 151 | } catch (IllegalArgumentException e) { 152 | throw new IllegalArgumentException("Failed to parse '" + line + "'", e); 153 | } 154 | } 155 | 156 | private Value parseSourceValue(String src) { 157 | src = src.replaceAll("\\s+", ""); 158 | if (src.startsWith("[")) { 159 | if (src.contains("+")) { 160 | if (src.startsWith("[r0+") || src.startsWith("[r1+")) 161 | return parseValue(src.substring(4, src.length() - 1)); 162 | if (src.endsWith("+r0]") || src.endsWith("+r1]")) 163 | return parseValue(src.substring(1, src.length() - 4)); 164 | throw new IllegalArgumentException("Unexpected relative load: " 165 | + src); 166 | } else { 167 | if (src.equals("[r0]") || src.equals("[r1]")) 168 | return new Value(0); 169 | 170 | return parseValue(src.substring(1, src.length() - 1)); 171 | } 172 | } else { 173 | // Register load 174 | if (src.equals("r0")) 175 | return new Value(255); 176 | if (src.equals("r1")) 177 | return new Value(254); 178 | if (src.equals("r2")) 179 | return new Value(253); 180 | if (src.equals("r3")) 181 | return new Value(252); 182 | return parseValue(src); 183 | } 184 | } 185 | 186 | private OpSource parseSource(String src) { 187 | src = src.replaceAll("\\s+", ""); 188 | if (src.startsWith("[")) { 189 | if (src.contains("+")) { 190 | src = src.toLowerCase(); 191 | 192 | if (src.startsWith("[r0+") || src.endsWith("+r0]")) 193 | return OpSource.R0_RELATIVE_LOAD; 194 | if (src.startsWith("[r1+") || src.endsWith("+r1]")) 195 | return OpSource.R1_RELATIVE_LOAD; 196 | throw new IllegalArgumentException("Unexpected relative load: " 197 | + src); 198 | } else { 199 | if (src.equals("[r0]")) 200 | return OpSource.R0_RELATIVE_LOAD; 201 | if (src.equals("[r1]")) 202 | return OpSource.R1_RELATIVE_LOAD; 203 | return OpSource.CONSTANT_LOAD; 204 | } 205 | } else { 206 | if (src.equals("r0") || src.equals("r1") || src.equals("r2") || src.equals("r3")) 207 | return OpSource.CONSTANT_LOAD; 208 | 209 | return OpSource.CONSTANT; 210 | } 211 | } 212 | 213 | private Value parseValue(String value) { 214 | if (value == null) 215 | return null; 216 | 217 | if (value.equals("r0") || value.equals("r1")) 218 | throw new IllegalArgumentException("Illegal value name: " + value); 219 | 220 | if (value.matches("[0-9]+")) 221 | return new Value(Integer.parseInt(value)); 222 | 223 | return new Value(value); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /shapecpu/src/main/java/com/grack/shapecpu/CPU.java: -------------------------------------------------------------------------------- 1 | package com.grack.shapecpu; 2 | 3 | import com.grack.homomorphic.engine.Engine; 4 | import com.grack.homomorphic.ops.Bit; 5 | import com.grack.homomorphic.ops.NativeBitFactory; 6 | import com.grack.homomorphic.ops.State; 7 | import com.grack.homomorphic.ops.StateFactory; 8 | import com.grack.homomorphic.ops.Word; 9 | import com.grack.homomorphic.ops.WordAndBit; 10 | 11 | public class CPU implements Engine { 12 | private static final String ALU_CARRY = "alu_carry"; 13 | private static final String ALU_MINUS = "alu_minus"; 14 | private static final String ALU_ZERO = "alu_zero"; 15 | private static final String PC = "pc"; 16 | private static final String AC = "ac"; 17 | private static final String MEMORY = "memory"; 18 | 19 | public CPU() { 20 | } 21 | 22 | @Override 23 | public void initialize(NativeBitFactory factory, StateFactory stateFactory) { 24 | stateFactory.allocateBitRegister(ALU_CARRY); 25 | stateFactory.allocateBitRegister(ALU_MINUS); 26 | stateFactory.allocateBitRegister(ALU_ZERO); 27 | 28 | stateFactory.allocateWordRegister(AC, 8); 29 | stateFactory.allocateWordRegister(PC, 8); 30 | 31 | stateFactory.allocateWordArrayRegister(MEMORY, 13, 256); 32 | } 33 | 34 | private Word memoryRead(State state, Word[] memory, Word addr, int size) { 35 | // Unroll the first time through the loop 36 | Word b1 = addr.eq(0).and(memory[0].bits(size - 1, 0)); 37 | 38 | for (int row = 1; row < memory.length; row++) { 39 | b1 = b1.xor(addr.eq(row).and(memory[row].bits(size - 1, 0))); 40 | } 41 | 42 | state.debug("b1", b1, addr); 43 | 44 | return b1; 45 | } 46 | 47 | /** 48 | * Reads or writes a memory address to/from a register, depending on the 49 | * state of the write flag. 50 | */ 51 | private Word memoryAccess(State state, Word[] memory, Word addr, Word reg, 52 | Bit write) { 53 | Bit[] r = new Bit[memory.length]; 54 | 55 | // Unroll the first time through the loop 56 | r[0] = addr.eq(0); 57 | memory[0] = memory[0].setBits(7, 0, (r[0].and(write)).ifThen(reg, memory[0])); 58 | Word b1 = r[0].and(memory[0].bits(7, 0)); 59 | 60 | for (int row = 1; row < memory.length; row++) { 61 | r[row] = addr.eq(row); 62 | memory[row] = memory[row].setBits(7, 0, (r[row].and(write)).ifThen(reg, memory[row])); 63 | b1 = b1.xor(r[row].and(memory[row].bits(7, 0))); 64 | } 65 | 66 | state.debug("b1", b1, addr, reg, write); 67 | return b1; 68 | } 69 | 70 | public void tick(State state) { 71 | Word pc = state.getWordRegister(PC); 72 | Word ac = state.getWordRegister(AC); 73 | Bit alu_carry = state.getBitRegister(ALU_CARRY); 74 | Bit alu_minus = state.getBitRegister(ALU_MINUS); 75 | Bit alu_zero = state.getBitRegister(ALU_ZERO); 76 | Word[] memory = state.getWordArrayRegister(MEMORY); 77 | 78 | state.debug("***** tick *****"); 79 | 80 | state.debug("pc =", pc); 81 | state.debug("ac =", ac); 82 | 83 | Word cmd = memoryRead(state, memory, pc, 13); 84 | Word cmd_param = cmd.bits(7, 0); 85 | 86 | Word load_arg = memoryRead(state, memory, cmd_param, 8); 87 | 88 | state.debug("cmd =", cmd); 89 | state.debug("load_arg =", load_arg); 90 | 91 | // Bytecode looks like: 92 | // | address_flag[1] | cmd[4] | data[8] | 93 | Word cmd_op = cmd.bits(11, 8); 94 | 95 | // Decode 96 | Bit cmd_store = cmd_op.eq(15); // Store ac to memory 97 | Bit cmd_load = cmd_op.eq(14); // Load memory to ac 98 | Bit cmd_rol = cmd_op.eq(12); // Rotate left through alu_carry 99 | Bit cmd_ror = cmd_op.eq(13); // Rotate right through alu_carry 100 | Bit cmd_add = cmd_op.eq(11); // Add ac to immediate or indirect 101 | Bit cmd_clc = cmd_op.eq(10); // Clear carry 102 | Bit cmd_sec = cmd_op.eq(9); // Set carry 103 | Bit cmd_xor = cmd_op.eq(8); // XOR ac with immediate 104 | Bit cmd_and = cmd_op.eq(7); // AND ac with immediate 105 | Bit cmd_or = cmd_op.eq(6); // OR ac with immediate 106 | Bit cmd_beq = cmd_op.eq(5); // Branch if alu_zero 107 | Bit cmd_jmp = cmd_op.eq(4); // Branch unconditionally 108 | Bit cmd_la = cmd_op.eq(3); // Load indirect 109 | Bit cmd_bmi = cmd_op.eq(2); // Branch if alu_minus 110 | Bit cmd_cmp = cmd_op.eq(1); // Compare ac with immediate or 111 | // indirect 112 | 113 | state.debug("Command select: ", "cmd_op", cmd_op, "store:", cmd_store, 114 | "load:", cmd_load, "rol:", cmd_rol, "ror:", cmd_ror, "add:", 115 | cmd_add, "clc:", cmd_clc, "sec:", cmd_sec, "xor:", cmd_xor, 116 | "and:", cmd_and, "or:", cmd_or, "beq:", cmd_beq, "jmp:", 117 | cmd_jmp, "la:", cmd_la, "bmi:", cmd_bmi, "cmp:", cmd_cmp); 118 | 119 | // Address? 120 | Bit cmd_a = cmd.bit(12); 121 | 122 | state.debug("cmd_param:", cmd_param, "cmd_a:", cmd_a); 123 | 124 | // CMP (two's compliment, then add) 125 | Word b_cmp = cmd_a.ifThen(load_arg, cmd_param).not().add(state.one()) 126 | .add(ac); 127 | 128 | state.debug("cmp:", b_cmp); 129 | 130 | // ROR 131 | Bit carry_ror = ac.bit(0); 132 | Word b_ror = ac.shr(1); 133 | b_ror = b_ror.setBit(7, alu_carry); 134 | 135 | // ROL 136 | Bit carry_rol = ac.bit(7); 137 | Word b_rol = ac.bits(6, 0).shl(1, alu_carry); 138 | 139 | // ADD 140 | WordAndBit add_1 = ac.addWithCarry(cmd_param, alu_carry); 141 | WordAndBit add_2 = ac.addWithCarry(load_arg, alu_carry); 142 | Word b_add = cmd_a.ifThen(add_2.getWord(), add_1.getWord()); 143 | Bit carry_add = cmd_a.ifThen(add_2.getBit(), add_1.getBit()); 144 | 145 | state.debug("add1:", add_1.getWord(), add_1.getBit(), "add2:", 146 | add_2.getWord(), add_2.getBit(), "b_add:", b_add, "carry_add", 147 | carry_add); 148 | 149 | Word load_val = memoryAccess(state, memory, cmd_param, ac, cmd_store); 150 | 151 | Bit ac_unchanged = cmd_sec.xor(cmd_clc).xor(cmd_beq).xor(cmd_bmi) 152 | .xor(cmd_cmp).xor(cmd_jmp).xor(cmd_store); 153 | 154 | Word ac_new; 155 | ac_new = cmd_load.and(cmd_param); 156 | ac_new = ac_new.xor(cmd_ror.and(b_ror)); 157 | ac_new = ac_new.xor(cmd_rol.and(b_rol)); 158 | ac_new = ac_new.xor(cmd_add.and(b_add)); 159 | ac_new = ac_new.xor(cmd_and.and(ac.and(cmd_param))); 160 | ac_new = ac_new.xor(cmd_xor.and(ac.xor(cmd_param))); 161 | ac_new = ac_new.xor(cmd_or.and(ac.or(cmd_param))); 162 | ac_new = ac_new.xor(cmd_la.and(load_val)); 163 | ac_new = ac_new.xor(ac_unchanged.and(ac)); 164 | 165 | ac = ac_new; 166 | state.debug("ac =", ac); 167 | 168 | alu_zero = (cmd_cmp.ifThen(b_cmp.eq(0), ac.eq(0)).or(alu_zero 169 | .and(cmd_bmi.or(cmd_beq)))); 170 | 171 | alu_minus = cmd_cmp.ifThen(b_cmp.bit(7), alu_minus); 172 | 173 | alu_carry = cmd_add.ifThen( 174 | carry_add, 175 | cmd_rol.ifThen(carry_rol, cmd_ror.ifThen( 176 | carry_ror, 177 | cmd_clc.ifThen(state.zero(), 178 | cmd_sec.ifThen(state.one(), alu_carry))))); 179 | 180 | state.debug("carry:", alu_carry, "minus:", alu_minus, "zero:", alu_zero); 181 | 182 | Word pc_linear = pc.add(state.one()); 183 | 184 | pc = cmd_beq.ifThen( 185 | alu_zero.ifThen(cmd_param, pc_linear), 186 | cmd_bmi.ifThen(alu_minus.ifThen(cmd_param, pc_linear), 187 | cmd_jmp.ifThen(cmd_param, pc_linear))); 188 | 189 | // Update CPU state 190 | state.setBitRegister(ALU_CARRY, alu_carry); 191 | state.setBitRegister(ALU_MINUS, alu_minus); 192 | state.setBitRegister(ALU_ZERO, alu_zero); 193 | state.setWordRegister(AC, ac); 194 | state.setWordRegister(PC, pc); 195 | state.setWordArrayRegister(MEMORY, memory); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /hidecpu2/src/main/java/com/grack/hidecpu2/assembler/Parser.java: -------------------------------------------------------------------------------- 1 | package com.grack.hidecpu2.assembler; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.google.common.base.CharMatcher; 9 | import com.google.common.base.Splitter; 10 | import com.google.common.io.CharSource; 11 | import com.grack.hidecpu2.assembler.line.Line; 12 | import com.grack.hidecpu2.assembler.line.LineBuilder; 13 | 14 | public class Parser { 15 | private CharSource source; 16 | private Splitter OPCODE_SPLITTER = Splitter.on(CharMatcher.WHITESPACE) 17 | .trimResults().omitEmptyStrings().limit(2); 18 | private Splitter PARAM_SPLITTER = Splitter.on(',').trimResults() 19 | .omitEmptyStrings(); 20 | 21 | public Parser(CharSource source) { 22 | this.source = source; 23 | } 24 | 25 | public Program parse() throws IOException { 26 | Program program = new Program(); 27 | List lines = program.getLines(); 28 | source.readLines().forEach((line) -> { 29 | lines.add(parseLine(line)); 30 | }); 31 | 32 | return program; 33 | } 34 | 35 | private Line parseLine(String line) { 36 | try { 37 | LineBuilder lineBuilder = new LineBuilder(); 38 | if (line.indexOf('#') != -1) { 39 | lineBuilder.withComment(line.substring(line.indexOf("#") + 1)); 40 | line = line.substring(0, line.indexOf('#')); 41 | } 42 | 43 | line = line.trim(); 44 | if (line.isEmpty()) 45 | return lineBuilder.createEmpty(); 46 | 47 | if (line.matches("\\s*[a-zA-Z0-9_]+:.*")) { 48 | lineBuilder.withLabel(line.substring(0, line.indexOf(':')).trim()); 49 | line = line.substring(line.indexOf(':') + 1); 50 | } 51 | 52 | line = line.trim(); 53 | if (line.isEmpty()) 54 | return lineBuilder.createEmpty(); 55 | 56 | if (line.startsWith(".")) { 57 | return lineBuilder.createSegment(line.substring(1)); 58 | } 59 | 60 | Iterator pieces = OPCODE_SPLITTER.split(line).iterator(); 61 | 62 | String opcode = pieces.next().toLowerCase(); 63 | String params = pieces.hasNext() ? pieces.next() : null; 64 | 65 | switch (opcode) { 66 | case "data": { 67 | List data = new ArrayList<>(); 68 | for (String datum : PARAM_SPLITTER.split(params)) { 69 | data.add(parseValue(datum)); 70 | } 71 | return lineBuilder.createData(data.toArray(new Value[data.size()])); 72 | } 73 | case "mov": { 74 | Iterator it = PARAM_SPLITTER.split(params).iterator(); 75 | String left = it.next(); 76 | String right = it.next(); 77 | OpSource src; 78 | OpTarget target; 79 | Value value; 80 | if (left.startsWith("[")) { 81 | lineBuilder.withOpcode(Opcode.STORE); 82 | target = OpTarget.valueOf(right.toUpperCase()); 83 | src = parseSource(left); 84 | value = parseSourceValue(left); 85 | } else { 86 | lineBuilder.withOpcode(Opcode.LOAD); 87 | target = OpTarget.valueOf(left.toUpperCase()); 88 | src = parseSource(right); 89 | value = parseSourceValue(right); 90 | } 91 | return lineBuilder.createStandard(target, src, value); 92 | } 93 | case "swap": { 94 | Iterator it = PARAM_SPLITTER.split(params).iterator(); 95 | String left = it.next(); 96 | String right = it.next(); 97 | lineBuilder.withOpcode(Opcode.SWAP); 98 | OpSource src; 99 | OpTarget target; 100 | Value value; 101 | // We're generous with what we allow for swap since it is identical both ways 102 | if (left.startsWith("[")) { 103 | target = OpTarget.valueOf(right.toUpperCase()); 104 | src = parseSource(left); 105 | value = parseSourceValue(left); 106 | } else { 107 | target = OpTarget.valueOf(left.toUpperCase()); 108 | src = parseSource(right); 109 | value = parseSourceValue(right); 110 | } 111 | return lineBuilder.createStandard(target, src, value); 112 | } 113 | case "jump": 114 | lineBuilder.withOpcode(Opcode.JUMP); 115 | return lineBuilder.createStandard(null, parseSource(params), parseSourceValue(params)); 116 | case "clrc": 117 | lineBuilder.withOpcode(Opcode.SETFLAGS); 118 | // TODO 119 | return lineBuilder.createMaskValue(1, 0); 120 | case "setc": 121 | lineBuilder.withOpcode(Opcode.SETFLAGS); 122 | // TODO 123 | return lineBuilder.createMaskValue(1, 1); 124 | case "blt": 125 | case "blte": 126 | case "beq": 127 | case "bca": 128 | case "bgt": 129 | case "bgte": 130 | case "bne": 131 | case "bnc": 132 | lineBuilder.withOpcode(Opcode.BRA); 133 | BranchType branchType = BranchType.valueOf(opcode.substring(1) 134 | .toUpperCase()); 135 | return lineBuilder.createBranch(branchType, parseValue(params)); 136 | case "loop": 137 | case "cmp": 138 | case "add": 139 | case "sub": 140 | case "and": 141 | case "xor": 142 | case "or": { 143 | lineBuilder.withOpcode(Opcode.valueOf(opcode.toUpperCase())); 144 | Iterator it = PARAM_SPLITTER.split(params).iterator(); 145 | String left = it.next(); 146 | String right = it.next(); 147 | return lineBuilder.createStandard(OpTarget.valueOf(left.toUpperCase()), parseSource(right), 148 | parseSourceValue(right)); 149 | } 150 | case "halt": 151 | lineBuilder.withOpcode(Opcode.JUMP); 152 | return lineBuilder.createStandard(null, OpSource.CONSTANT, new Value("pc")); 153 | default: 154 | throw new RuntimeException("Invalid opcode: " + opcode); 155 | } 156 | } catch (IllegalArgumentException e) { 157 | throw new IllegalArgumentException("Failed to parse '" + line + "'", e); 158 | } 159 | } 160 | 161 | private Value parseSourceValue(String src) { 162 | src = src.replaceAll("\\s+", ""); 163 | if (src.startsWith("[")) { 164 | if (src.contains("+")) { 165 | if (src.startsWith("[r0+") || src.startsWith("[r1+")) 166 | return parseValue(src.substring(4, src.length() - 1)); 167 | if (src.endsWith("+r0]") || src.endsWith("+r1]")) 168 | return parseValue(src.substring(1, src.length() - 4)); 169 | throw new IllegalArgumentException("Unexpected relative load: " 170 | + src); 171 | } else { 172 | if (src.equals("[r0]") || src.equals("[r1]")) 173 | return new Value(0); 174 | 175 | return parseValue(src.substring(1, src.length() - 1)); 176 | } 177 | } else { 178 | // Register load 179 | if (src.matches("r[0-3]")) 180 | return new Value(OpTarget.values()[src.charAt(1) - '0']); 181 | return parseValue(src); 182 | } 183 | } 184 | 185 | private OpSource parseSource(String src) { 186 | src = src.replaceAll("\\s+", ""); 187 | if (src.startsWith("[")) { 188 | if (src.contains("+")) { 189 | src = src.toLowerCase(); 190 | 191 | if (src.startsWith("[r0+") || src.endsWith("+r0]")) 192 | return OpSource.R0_RELATIVE_LOAD; 193 | if (src.startsWith("[r1+") || src.endsWith("+r1]")) 194 | return OpSource.R1_RELATIVE_LOAD; 195 | throw new IllegalArgumentException("Unexpected relative load: " 196 | + src); 197 | } else { 198 | if (src.equals("[r0]")) 199 | return OpSource.R0_RELATIVE_LOAD; 200 | if (src.equals("[r1]")) 201 | return OpSource.R1_RELATIVE_LOAD; 202 | return OpSource.CONSTANT_LOAD; 203 | } 204 | } else { 205 | if (src.equals("r0") || src.equals("r1") || src.equals("r2") || src.equals("r3")) 206 | return OpSource.CONSTANT_LOAD; 207 | 208 | return OpSource.CONSTANT; 209 | } 210 | } 211 | 212 | private Value parseValue(String value) { 213 | if (value == null) 214 | return null; 215 | 216 | if (value.equals("r0") || value.equals("r1")) 217 | throw new IllegalArgumentException("Illegal value name: " + value); 218 | 219 | if (value.matches("[0-9]+")) 220 | return new Value(Integer.parseInt(value)); 221 | 222 | return new Value(value); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /hidecpu2/opcodes.v2.md: -------------------------------------------------------------------------------- 1 | # HideCPU 2 | 3 | The HideCPU is a CPU with separate eight-bit data and 16-bit code spaces, each with a maximum size of 256 bytes. Instructions are encoded as 16 bits in the code space (four for the opcode and 12 for the opcode data), while data is represented as eight bits in the data space. Instructions are immutable and there is currently no way to read or write them. 4 | 5 | The HideCPU has four eight-bit registers: r0-r3. r0 and r1 can be used for relative addressing and arithmetic, while r2 and r3 are for arithmetic only. 6 | 7 | The registers and flags are aliases of memory locations to simplify the instruction format. The layout of these locations in memory is: 8 | 9 | * 0x00: r0 10 | * 0x01: r1 11 | * 0x02: r2 12 | * 0x03: r3 13 | * 0x04: cr 14 | * 0x05: flags 15 | * 0x06: pc 16 | * 0x07: lr 17 | 18 | ## Assembler Opcodes 19 | 20 | Note: the assembler opcodes aren't a one-to-one match with the machine opcodes. 21 | 22 | ### Common form 23 | 24 | Most assembler opcodes consist of the form: 25 | 26 | op target, source 27 | 28 | Target is one of the registers, r0-r3. Source is either a constant, a constant-relative load, or a constant load relative to r0 or r1. 29 | 30 | ### mov (load/store) 31 | 32 | `mov (r0-r4,flags,pc,lr), (constant|constant-load|r0-relative|r1-relative|r0-r4|flags|pc|lr)` 33 | 34 | Operates as a load. If loading from one register to another, the memory location for the register is used instead. `load0` is used for r0-r3, `load1` for r4 and other registers. 35 | 36 | `mov (constant-store|r0-relative|r1-relative), (r0-r3)` 37 | 38 | Store operation, placing the contents in memory either in a constant location 39 | or relative to r0/r1. The `constant` instruction form is unused and undefined. 40 | 41 | Special forms: 42 | 43 | * `ret`: `mov pc, lr` 44 | * `bsub dst`: `mov lr, pc+8`, `mov pc, dst` 45 | * `bra dst`: `mov pc, dst` 46 | * `halt`: `mov pc, pc` 47 | * `mov lr, pc`: `mov lr, (constant)` 48 | 49 | Examples: 50 | 51 | `mov r0, [r0+10] => r0 = *(r0 + 10)` 52 | 53 | ### math 54 | 55 | `(add|sub|and|or|xor) (r0-r3), (constant|constant-load|r0-relative|r1-relative|r0-r4|flags|pc|lr)` 56 | 57 | Loads the source and target, applies a mathematical or binary operation to it, then stores 58 | it back into the target register. 59 | 60 | Special forms: 61 | 62 | * `inc r0`: `add r0, 1` 63 | * `dec r0`: `sub r0, 1` 64 | * `not r0`: `xor r0, 255` 65 | 66 | Examples: 67 | 68 | `add r0, [r0+10] => r0 = r0 + *(r0 + 10)` 69 | 70 | ### swap 71 | 72 | `swap (r0-r3), (constant-load|r0-relative|r1-relative|r0-r4|flags|pc|lr)` 73 | 74 | Loads the source and target, swaps them and stores them back. The `constant` instruction form is unused and undefined. 75 | 76 | ### unary 77 | 78 | `(shl|shr|rol|rolc|ror|rorc|neg|swapn) rX` 79 | `(shl|shr|rol|ror) rX, cr` 80 | 81 | Unary op applied to a register rX. 82 | 83 | | mnemonic | description | 84 | |---|---| 85 | | shl | Shift left | 86 | | shr | Shift right | 87 | | rol | Rotate left | 88 | | rolc | Rotate left through carry | 89 | | ror | Rotate right | 90 | | rorc | Rotate right through carry | 91 | | neg | 2s compliment | 92 | | swapn | Swap nibbles (`aaaabbbb` -> `bbbbaaaa`) | 93 | 94 | ### cmp 95 | 96 | `cmp (r0-r3), (constant|constant-load|r0-relative|r1-relative|r0-r4|flags|pc|lr)` 97 | 98 | Compares the source and target registers, setting the minus, and zero flags appropriately. 99 | 100 | Examples: 101 | 102 | ``` 103 | cmp r0, [r0+10] 104 | => minus = r0 < *(r0 + 10), zero = r0 == *(r0 + 10) 105 | ``` 106 | 107 | ### flags 108 | 109 | `setflags mask, values` 110 | 111 | Set the flags to `(flags & ~mask) | (mask & values)` 112 | 113 | Special forms: 114 | 115 | * setc: setflags ca, ca 116 | * clc: setflags ca, 0 117 | * setz: setflags eq, eq 118 | * clz: setflags eq, 0 119 | 120 | ### branch 121 | 122 | `b[flags] constant` 123 | 124 | Conditional branch to constant address based on status registers: `alu_minus`, `alu_zero`, `alu_carry`, `alu_xtra`. 125 | 126 | | flags | test | 127 | |---|---| 128 | | lt | minus == 1 && zero == 0 | 129 | | lte | !(minus == 0 && zero == 0) | 130 | | gt | minus == 0 && zero == 0 | 131 | | gte | !(minus == 1 && zero == 0) | 132 | | eq | zero == 1 | 133 | | ne | !(zero == 1) | 134 | | ca | carry == 1 | 135 | | nc | !(carry == 1) | 136 | | mi | minus == 1 | 137 | | nm | !(minus == 1) | 138 | | xt1 | xtra1 == 1 | 139 | | nx1 | !(xtra1 == 1) | 140 | | xt2 | xtra2 == 1 | 141 | | nx2 | !(xtra2 == 1) | 142 | | xt3 | xtra3 == 1 | 143 | | nx3 | !(xtra3 == 1) | 144 | 145 | 146 | ### loop 147 | 148 | `loop (r0-r3), (constant|constant-load|r0-relative|r1-relative)` 149 | 150 | Decrements the target register and jumps if the register was zero before decrementing. 151 | 152 | ## Machine Opcodes 153 | 154 | ### Opcodes 155 | 156 | | opcode | mnemonic | encoding | description | 157 | |---|---|---|---| 158 | |0 |load0 rX, loc |(a)|load rX from loc 159 | |1 |store0 rX, loc |(a)|store rX to loc 160 | |2 |add rX, loc |(a)|rX = rX + loc 161 | |3 |sub rX, loc |(a)|rX = rX - loc 162 | |4 |and rX, loc |(a)|rX = rX & loc 163 | |5 |or rX, loc |(a)|rX = rX \| loc 164 | |6 |xor rX, loc |(a)|rX = rX ^ loc 165 | |7 |cmp rX, loc |(a)|set minus, zero 166 | |8 |load1 rX, loc |(a)|load r(X+4) from loc 167 | |9 |store1 rX, loc |(a)|store r(X+4) to loc 168 | |10 |swap rX, loc |(a)|swap rX and loc 169 | |11 |loop rX, loc |(a)|decrement and jump if not zero 170 | |12 |unary rX, op |(b)|op = shl, shr, rol, ror, etc. 171 | |13 |setflags mask, flags |(c)|set/clear flags based on mask 172 | |14 |bra invert, flags, target|(d)|branch based on flags 173 | |15 |mul rX, loc |(e)|r0:r1 = rX * loc 174 | 175 | Encodings: 176 | 177 | * (a): `aaaa bb cc dddddddd` 178 | * (b): `aaaa bb XX cccccccc` 179 | * (c): `aaaa bbbbbb cccccc` 180 | * (d): `aaaa b ccc dddddddd` 181 | * (e): `aaaa bb c ddd` 182 | 183 | ### Encoding A (standard) 184 | 185 | The majority of opcodes are encoded using target/source/data like so: 186 | 187 | aaaa bb cc dddddddd 188 | a = opcode 189 | b = target register (source for store) 190 | c = source type 191 | d = data 192 | 193 | #### Target argument 194 | 195 | 00: r0 196 | 01: r1 197 | 10: r2 198 | 11: r3 199 | 200 | #### Source argument 201 | 202 | 00 (load): constant # load this instruction's data directly as a constant 203 | 00 (store): register # store this instructions output to a register 204 | 01: [constant] # load from data space indirectly using this instruction's data 205 | 10: [r0 + constant] 206 | 11: [r1 + constant] 207 | 208 | ### Encoding B (unary) 209 | 210 | Unary opcodes operate on a register only. The sub-op is encoded in the instruction like so: 211 | 212 | aaaa bb XX ccccdddd 213 | a = opcode 214 | b = target register 215 | c = sub-op 216 | d = argument 217 | 218 | #### Target argument 219 | 220 | 00: r0 221 | 01: r1 222 | 10: r2 223 | 11: r3 224 | 225 | #### Sub-op 226 | 227 | The sub-op is a 4-bit selector for one of the possible 16 sub-ops, mainly using the barrel shifter: 228 | 229 | | subop | mnemonic | description | 230 | |---|---|---| 231 | |0000| shl.n | Shift left by n (constant) | 232 | |0001| shr.n | Shift right by n (constant) | 233 | |0010| rol.n | Rotate left by n (constant) | 234 | |0011| ror.n | Rotate right by n (constant) | 235 | |0100| rolc | Rotate left through carry | 236 | |0101| rorc | Rotate right through carry | 237 | |0110| unused | unused | 238 | |0111| unused | unused | 239 | |1000| shl.cr | Shift left by cr | 240 | |1001| shr.cr | Shift right by cr | 241 | |1010| rol.cr | Rotate left by cr | 242 | |1011| ror.cr | Rotate right by cr | 243 | |1100| adc | If carry is set, adds 1 | 244 | |1101| sbm | If minus is set, subtracts 1 | 245 | |1110| neg | 2s compliment | 246 | |1111| loadro | Loads instruction data from code segment to r0:r1 | 247 | 248 | #### Argument 249 | 250 | The argument is four bits, used only for the bit shifting operations. If the high bit is one, the lowest two bits select a register. If the the high bit is zero, the lowest three bits specify an immediate value. 251 | 252 | 253 | 254 | ### Encoding C (setflags) 255 | 256 | `setflags` has a unique encoding for the mask and flag values: 257 | 258 | aaaa bbbbbb cccccc 259 | a = opcode 260 | b = mask 261 | c = flags 262 | 263 | ### Encoding D (branch) 264 | 265 | Branch operations require the flags to test and a constrant address like so: 266 | 267 | aaaa b ccc dddddddd 268 | a = opcode 269 | b = invert 270 | c = flags 271 | d = constant address 272 | 273 | #### Flags 274 | 275 | |invert|flags|mnemonic| 276 | |---|---|---| 277 | |0|000|lt| 278 | |0|001|gt| 279 | |0|010|eq| 280 | |0|011|ca| 281 | |0|100|mi| 282 | |0|101|x1| 283 | |0|110|x2| 284 | |0|111|x3| 285 | |1|000|gte| 286 | |1|001|lte| 287 | |1|010|ne| 288 | |1|011|nc| 289 | |1|100|nm| 290 | |1|101|nx1| 291 | |1|110|nx2| 292 | |1|111|nx3| 293 | 294 | ### Encoding E (mul) 295 | 296 | Multiply operations require a signed flag, a source and a multiplier: 297 | 298 | aaaa b cc d X eeeeeeee 299 | a = opcode 300 | b = signed 301 | c = source multiplicand 302 | d = multiplier selection 303 | e = multiplier 304 | 305 | #### Source argument 306 | 307 | 00: r0 308 | 01: r1 309 | 10: r2 310 | 11: r3 311 | 312 | #### Multiplier selection 313 | 314 | 0: register (multiplier is an index to register) 315 | 1: constant 316 | 317 | 318 | ### Load/store 319 | 320 | ``` 321 | # Load indirect 322 | mov r0, [r0] 323 | mov r0, label \_ same encoding (load) 324 | mov r0, constant / 325 | mov r0, [label] \__ same encoding (load) 326 | mov r0, [constant] / 327 | mov [r1], r0 <-- store 328 | ``` 329 | --------------------------------------------------------------------------------