├── .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 [](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 |
--------------------------------------------------------------------------------