├── LICENSE
├── README.md
├── apps
├── .gitignore
├── circuit
│ ├── GNUmakefile
│ └── main.go
├── garbled
│ ├── GNUmakefile
│ ├── bmr.go
│ ├── compile.go
│ ├── default.pgo
│ ├── examples
│ │ ├── 3party.qcl
│ │ ├── add.qcl
│ │ ├── aes128.qcl
│ │ ├── aesblock.qcl
│ │ ├── aesblock2.qcl
│ │ ├── aescbc.qcl
│ │ ├── aesexpand.qcl
│ │ ├── aesgcm.qcl
│ │ ├── and.qcl
│ │ ├── bug.qcl
│ │ ├── call.qcl
│ │ ├── call2.qcl
│ │ ├── constant.qcl
│ │ ├── credit.qcl
│ │ ├── crypto.qcl
│ │ ├── div.qcl
│ │ ├── ed25519.qcl
│ │ ├── ed25519
│ │ │ ├── keygen.qcl
│ │ │ └── sign.qcl
│ │ ├── encrypt.qcl
│ │ ├── hamming.qcl
│ │ ├── hmac-sha256.qcl
│ │ ├── hmac.qcl
│ │ ├── key-import.qcl
│ │ ├── max.qcl
│ │ ├── max3.qcl
│ │ ├── millionaire.qcl
│ │ ├── montgomery.qcl
│ │ ├── mult.qcl
│ │ ├── mult1024.qcl
│ │ ├── nc.qcl
│ │ ├── parametrized-main.qcl
│ │ ├── pkg.qcl
│ │ ├── ptr.qcl
│ │ ├── rps.qcl
│ │ ├── rsa.qcl
│ │ ├── rsasign.qcl
│ │ ├── sha256.qcl
│ │ ├── sha512.qcl
│ │ └── sort.qcl
│ ├── main.go
│ ├── result.go
│ └── streaming.go
├── iotest
│ ├── iotest.go
│ └── main.go
└── iter
│ └── main.go
├── circuit
├── aesni
│ ├── .gitignore
│ ├── GNUmakefile
│ ├── c
│ │ └── aesni.c
│ └── go_test.go
├── analyze.go
├── circuit.go
├── circuit_test.go
├── computer.go
├── dot.go
├── enc_test.go
├── eval.go
├── evaluator.go
├── garble.go
├── garbler.go
├── ioarg.go
├── ioarg_test.go
├── marshal.go
├── parser.go
├── parser_test.go
├── player.go
├── stream_evaluator.go
├── stream_garble.go
├── stream_garble_test.go
├── svg.go
├── template.go
├── template_test.go
└── timing.go
├── compiler
├── .gitignore
├── arithmetic_test.go
├── ast
│ ├── ast.go
│ ├── builtin.go
│ ├── codegen.go
│ ├── eval.go
│ ├── package.go
│ └── ssagen.go
├── circuits
│ ├── allocator.go
│ ├── circ_adder.go
│ ├── circ_binary.go
│ ├── circ_comparators.go
│ ├── circ_divider.go
│ ├── circ_hamming.go
│ ├── circ_index.go
│ ├── circ_multiplier.go
│ ├── circ_multiplier_params.go
│ ├── circ_mux.go
│ ├── circ_subtractor.go
│ ├── circuits_test.go
│ ├── compiler.go
│ ├── gates.go
│ ├── wire.go
│ └── wire_test.go
├── compiler.go
├── compiler_test.go
├── lexer.go
├── lexer_test.go
├── parser.go
├── parser_test.go
├── ssa
│ ├── bindings.go
│ ├── bindings_test.go
│ ├── block.go
│ ├── circuitgen.go
│ ├── generator.go
│ ├── instructions.go
│ ├── peephole.go
│ ├── program.go
│ ├── set.go
│ ├── streamer.go
│ ├── value.go
│ ├── value_test.go
│ └── wire_allocator.go
├── ssagen_test.go
├── tests
│ ├── array.qcl
│ ├── assign2.qcl
│ ├── composite_lit.qcl
│ ├── const_int.qcl
│ ├── constmod.qcl
│ ├── copy_ptr.qcl
│ ├── copy_slice_eq.qcl
│ ├── copy_slice_gt.qcl
│ ├── copy_slice_lt.qcl
│ ├── div.qcl
│ ├── for.qcl
│ ├── hmac_sha256.qcl
│ ├── len_array.qcl
│ ├── len_array_sum.qcl
│ ├── len_string.qcl
│ ├── len_string_sum.qcl
│ ├── lshift0.qcl
│ ├── lshift1.qcl
│ ├── lshift64.qcl
│ ├── make.qcl
│ ├── mod.qcl
│ ├── mult.qcl
│ ├── named_return.qcl
│ ├── pkg.qcl
│ ├── ptr.qcl
│ ├── ptr_array.qcl
│ ├── ptr_array_get.qcl
│ ├── ptr_arrays.qcl
│ ├── ptr_scopes.qcl
│ ├── ptr_struct_field.qcl
│ ├── rsa.qcl
│ ├── rshift0.qcl
│ ├── rshift1.qcl
│ ├── rshift64.qcl
│ ├── sha256_block.qcl
│ ├── sha256_block_block.qcl
│ ├── sha256_block_pad.qcl
│ ├── sha512_block.qcl
│ ├── sha512_block_block.qcl
│ ├── sha512_block_pad.qcl
│ ├── slice.qcl
│ ├── sub.qcl
│ ├── test_ge.qcl
│ ├── test_gt.qcl
│ ├── test_le.qcl
│ ├── test_lt.qcl
│ ├── var.qcl
│ ├── var2.qcl
│ ├── var3.qcl
│ └── zerolabel.qcl
├── testsuite_test.go
└── utils
│ ├── logger.go
│ ├── params.go
│ ├── point.go
│ └── point_test.go
├── go.mod
├── go.sum
├── ot
├── README.md
├── co.go
├── co_test.go
├── io.go
├── label.go
├── label_test.go
├── mpint
│ ├── mpint.go
│ └── mpint_test.go
├── ot.go
├── ot_test.go
├── pipe.go
└── pipe_test.go
├── p2p
├── network.go
├── protocol.go
└── protocol_test.go
├── pkg
├── README.md
├── bits
│ └── integer.qcl
├── builtin.qcl
├── bytes
│ ├── bytes.go
│ ├── bytes.qcl
│ └── doc.qcl
├── crypto
│ ├── aes
│ │ ├── aes_128.circ
│ │ ├── aes_192.circ
│ │ ├── aes_256.circ
│ │ ├── block.qcl
│ │ ├── cipher.qcl
│ │ ├── circuit.qcl
│ │ └── const.qcl
│ ├── bloom
│ │ └── bloom.qcl
│ ├── cipher
│ │ ├── cbc
│ │ │ └── cbc.qcl
│ │ └── gcm
│ │ │ └── gcm.qcl
│ ├── ed25519
│ │ ├── README.md
│ │ ├── internal
│ │ │ └── edwards25519
│ │ │ │ ├── const.qcl
│ │ │ │ └── ed25519.qcl
│ │ ├── keygen.qcl
│ │ └── sign.qcl
│ ├── ed448
│ │ ├── constants.qcl
│ │ ├── curve.qcl
│ │ ├── fp.qcl
│ │ ├── fp_generic.qcl
│ │ ├── fp_noasm.qcl
│ │ ├── goldilocks.qcl
│ │ ├── isogeny.qcl
│ │ ├── mlsbset.qcl
│ │ ├── point.qcl
│ │ ├── power.qcl
│ │ ├── scalar.qcl
│ │ ├── sign
│ │ │ └── ed448.qcl
│ │ ├── twist.qcl
│ │ ├── twistPoint.qcl
│ │ ├── twistTables.qcl
│ │ ├── twist_basemult.qcl
│ │ └── wnaf.qcl
│ ├── hmac
│ │ ├── doc.qcl
│ │ ├── sha256.qcl
│ │ └── sha512.qcl
│ ├── rsa
│ │ └── rsa.qcl
│ ├── sha256
│ │ ├── sha256.circ
│ │ └── sum.qcl
│ ├── sha3
│ │ ├── sha3.go
│ │ └── sha3.qcl
│ ├── sha512
│ │ ├── sha512.circ
│ │ ├── sha512.qclc
│ │ └── sum.qcl
│ └── subtle
│ │ └── funcs.qcl
├── embedded.go
├── encoding
│ ├── binary
│ │ ├── bigendian.qcl
│ │ ├── doc.qcl
│ │ ├── getput.qcl
│ │ ├── littleendian.qcl
│ │ └── metrics.qcl
│ └── hex
│ │ ├── doc.qcl
│ │ └── hex.qcl
├── math
│ ├── add64.circ
│ ├── const.qcl
│ ├── div64.circ
│ ├── doc.qcl
│ ├── integer.qcl
│ ├── modp.qcl
│ ├── montgomery.qcl
│ ├── mul64.circ
│ └── sub64.circ
└── sort
│ └── sort.qcl
└── types
├── parse.go
├── parse_test.go
├── types.go
└── types_test.go
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Markku Rossi
4 | Modifications Copyright (c) 2024 Quilibrium, Inc.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bedlam
2 |
3 | This project is a very heavy fork of Markku Rossi's
4 | [MPCL](https://github.com/markkurossi/mpc) library and is in heavy development.
5 |
6 | Directionally we differ on a few levels:
7 | - larger subset of golang support (in particular, supporting receiver functions)
8 | - fixed parser bugs
9 | - integration with additional OT-based primitives
10 | - built to slot into hypergraph execution
11 | - embedded FS to QCL/primitive circuits
12 | - support for more advanced OT primitives (currently disabled in public preview)
13 |
--------------------------------------------------------------------------------
/apps/.gitignore:
--------------------------------------------------------------------------------
1 | *.circ
2 |
--------------------------------------------------------------------------------
/apps/circuit/GNUmakefile:
--------------------------------------------------------------------------------
1 | CIRCUITS=$(wildcard *.circ)
2 | PDFS=$(patsubst %.circ,%.pdf,$(CIRCUITS))
3 | PNGS=$(patsubst %.circ,%.png,$(CIRCUITS))
4 |
5 | all: $(PDFS) $(PNGS)
6 |
7 | clean:
8 | $(RM) $(PDFS) $(PNGS)
9 |
10 | %.pdf: %.eps
11 | ps2pdf -sPAPERSIZE=a4 $<
12 |
13 | %.eps: %.dot
14 | dot -Tps -Gorientation=land -Gsize="11,7.5" $< > $@
15 |
16 | %.png: %.dot
17 | dot -Tpng $< > $@
18 |
19 | %.dot: %.circ
20 | ./circuit $< > $@
21 |
--------------------------------------------------------------------------------
/apps/circuit/main.go:
--------------------------------------------------------------------------------
1 | //
2 | // main.go
3 | //
4 | // Copyright (c) 2019-2022 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package main
10 |
11 | import (
12 | "flag"
13 | "fmt"
14 | "log"
15 |
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
17 | )
18 |
19 | func main() {
20 | flag.Parse()
21 |
22 | for _, file := range flag.Args() {
23 | c, err := circuit.Parse(file)
24 | if err != nil {
25 | log.Fatal(err)
26 | }
27 |
28 | fmt.Printf("digraph circuit\n{\n")
29 | fmt.Printf(" overlap=scale;\n")
30 | fmt.Printf(" node\t[fontname=\"Helvetica\"];\n")
31 | fmt.Printf(" {\n node [shape=plaintext];\n")
32 | for w := 0; w < c.NumWires; w++ {
33 | fmt.Printf(" w%d\t[label=\"%d\"];\n", w, w)
34 | }
35 | fmt.Printf(" }\n")
36 |
37 | fmt.Printf(" {\n node [shape=box];\n")
38 | for idx, gate := range c.Gates {
39 | fmt.Printf(" g%d\t[label=\"%s\"];\n", idx, gate.Op)
40 | }
41 | fmt.Printf(" }\n")
42 |
43 | if true {
44 | fmt.Printf(" { rank=same")
45 | for w := 0; w < c.Inputs.Size(); w++ {
46 | fmt.Printf("; w%d", w)
47 | }
48 | fmt.Printf(";}\n")
49 |
50 | fmt.Printf(" { rank=same")
51 | for w := 0; w < c.Outputs.Size(); w++ {
52 | fmt.Printf("; w%d", c.NumWires-w-1)
53 | }
54 | fmt.Printf(";}\n")
55 | }
56 |
57 | for idx, gate := range c.Gates {
58 | for _, i := range gate.Inputs() {
59 | fmt.Printf(" w%d -> g%d;\n", i, idx)
60 | }
61 | fmt.Printf(" g%d -> w%d;\n", idx, gate.Output)
62 | }
63 | fmt.Printf("}\n")
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/apps/garbled/GNUmakefile:
--------------------------------------------------------------------------------
1 |
2 | programs := $(wildcard examples/*.qcl)
3 | circs := $(patsubst %.qcl,%.circ,$(programs))
4 | qclcs := $(patsubst %.qcl,%.qclc,$(programs))
5 | bristols := $(patsubst %.qcl,%.bristol,$(programs))
6 | ssas := $(patsubst %.qcl,%.ssa,$(programs))
7 | dots := $(patsubst %,%.dot,$(circs) $(qclcs) $(bristols) $(ssas))
8 | svgs := $(patsubst %.dot,%.svg,$(dots))
9 |
10 | generated_dots := $(wildcard examples/*.dot)
11 | generated_svgs := $(patsubst %.dot,%.svg,$(generated_dots))
12 |
13 | all: $(generated_svgs)
14 |
15 | %.svg: %.dot
16 | dot -Tsvg $+ > $@
17 |
18 | clean:
19 | @rm -f $(circs) $(qclcs) $(bristols) $(ssas) $(dots) $(svgs)
20 |
--------------------------------------------------------------------------------
/apps/garbled/bmr.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package main
8 |
9 | import (
10 | "fmt"
11 | "log"
12 |
13 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
14 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
15 | "source.quilibrium.com/quilibrium/monorepo/bedlam/p2p"
16 | )
17 |
18 | func bmrMode(file string, params *utils.Params, player int) error {
19 | fmt.Printf("semi-honest secure BMR protocol\n")
20 | fmt.Printf("player: %d\n", player)
21 |
22 | circ, err := loadCircuit(file, params, nil)
23 | if err != nil {
24 | return err
25 | }
26 |
27 | if player >= len(circ.Inputs) {
28 | return fmt.Errorf("invalid party number %d for %d-party computation",
29 | player, len(circ.Inputs))
30 | }
31 |
32 | input, err := circ.Inputs[player].Parse(inputFlag)
33 | if err != nil {
34 | return err
35 | }
36 |
37 | for idx, arg := range circ.Inputs {
38 | if idx == player {
39 | fmt.Printf(" + In%d: %s\n", idx, arg)
40 | } else {
41 | fmt.Printf(" - In%d: %s\n", idx, arg)
42 | }
43 | }
44 |
45 | fmt.Printf(" - Out: %s\n", circ.Outputs)
46 | fmt.Printf(" - In: %s\n", inputFlag)
47 |
48 | // Create network.
49 | addr := makeAddr(player)
50 | nw, err := p2p.NewNetwork(addr, player)
51 | if err != nil {
52 | return err
53 | }
54 | defer nw.Close()
55 |
56 | numPlayers := len(circ.Inputs)
57 |
58 | for i := 0; i < numPlayers; i++ {
59 | if i == player {
60 | continue
61 | }
62 | err := nw.AddPeer(makeAddr(i), i)
63 | if err != nil {
64 | return err
65 | }
66 | }
67 |
68 | log.Printf("Network created\n")
69 |
70 | result, err := circuit.Player(nw, circ, input, verbose)
71 | if err != nil {
72 | return err
73 | }
74 |
75 | printResults(result, circ.Outputs)
76 | return nil
77 | }
78 |
79 | func makeAddr(player int) string {
80 | return fmt.Sprintf("127.0.0.1:%d", 8080+player)
81 | }
82 |
--------------------------------------------------------------------------------
/apps/garbled/compile.go:
--------------------------------------------------------------------------------
1 | //
2 | // main.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package main
10 |
11 | import (
12 | "bufio"
13 | "fmt"
14 | "io"
15 | "os"
16 | "strings"
17 |
18 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
19 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler"
20 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
21 | )
22 |
23 | func compileFiles(files []string, params *utils.Params,
24 | compile, ssa, dot, svg bool, circFormat string) error {
25 |
26 | var circ *circuit.Circuit
27 | var err error
28 |
29 | for _, file := range files {
30 | if compile {
31 | params.CircOut, err = makeOutput(file, circFormat)
32 | if err != nil {
33 | return err
34 | }
35 | params.CircFormat = circFormat
36 | if dot {
37 | params.CircDotOut, err = makeOutput(file, "circ.dot")
38 | if err != nil {
39 | return err
40 | }
41 | }
42 | if svg {
43 | params.CircSvgOut, err = makeOutput(file, "circ.svg")
44 | if err != nil {
45 | return err
46 | }
47 | }
48 | }
49 | if circuit.IsFilename(file) {
50 | circ, err = circuit.Parse(file)
51 | if err != nil {
52 | return err
53 | }
54 | if params.CircOut != nil {
55 | if params.Verbose {
56 | fmt.Printf("Serializing circuit...\n")
57 | }
58 | err = circ.MarshalFormat(params.CircOut, params.CircFormat)
59 | if err != nil {
60 | return err
61 | }
62 | }
63 | } else if strings.HasSuffix(file, ".qcl") {
64 | if ssa {
65 | params.SSAOut, err = makeOutput(file, "ssa")
66 | if err != nil {
67 | return err
68 | }
69 | if dot {
70 | params.SSADotOut, err = makeOutput(file, "ssa.dot")
71 | if err != nil {
72 | return err
73 | }
74 | }
75 | }
76 | circ, _, err = compiler.New(params).CompileFile(file, nil)
77 | if err != nil {
78 | return err
79 | }
80 | } else {
81 | return fmt.Errorf("unknown file type '%s'", file)
82 | }
83 | }
84 | return nil
85 | }
86 |
87 | func makeOutput(base, suffix string) (io.WriteCloser, error) {
88 | var path string
89 |
90 | idx := strings.LastIndexByte(base, '.')
91 | if idx < 0 {
92 | path = base + "." + suffix
93 | } else {
94 | path = base[:idx+1] + suffix
95 | }
96 | f, err := os.Create(path)
97 | if err != nil {
98 | return nil, err
99 | }
100 | return &OutputFile{
101 | File: f,
102 | Buffered: bufio.NewWriter(f),
103 | }, nil
104 | }
105 |
106 | // OutputFile implements a buffered output file.
107 | type OutputFile struct {
108 | File *os.File
109 | Buffered *bufio.Writer
110 | }
111 |
112 | func (out *OutputFile) Write(p []byte) (nn int, err error) {
113 | return out.Buffered.Write(p)
114 | }
115 |
116 | // Close implements io.Closer.Close for the buffered output file.
117 | func (out *OutputFile) Close() error {
118 | if err := out.Buffered.Flush(); err != nil {
119 | return err
120 | }
121 | return out.File.Close()
122 | }
123 |
--------------------------------------------------------------------------------
/apps/garbled/default.pgo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QuilibriumNetwork/bedlam/80c689d8e0699b5f5a71dde4caac54bcfa506751/apps/garbled/default.pgo
--------------------------------------------------------------------------------
/apps/garbled/examples/3party.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b, e uint1) uint {
6 | return a & b & e
7 | }
8 |
--------------------------------------------------------------------------------
/apps/garbled/examples/add.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | import (
7 | "math"
8 | )
9 |
10 | func main(a, b uint64) uint {
11 | return a + b
12 | //return math.AddUint64(a, b)
13 | }
14 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aes128.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/aes"
7 | )
8 |
9 | func main(a, b int8) []byte {
10 | var key [16]byte
11 | for i := 0; i < len(key); i++ {
12 | key[i] = i
13 | }
14 |
15 | var data [16]byte
16 | for i := 0; i < len(data); i++ {
17 | data[i] = i
18 | }
19 |
20 | return aes.Block128(key, data)
21 | }
22 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aesblock.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/aes"
7 | )
8 |
9 | func main(key, data [16]byte) []byte {
10 | return aes.EncryptBlock(key, data)
11 | }
12 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aesblock2.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/aes"
7 | )
8 |
9 | func main(key, data [16]byte) []byte {
10 | return aes.Block128(key, data)
11 | }
12 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aescbc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/cipher/cbc"
7 | )
8 |
9 | // Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key
10 | // Key : 0x06a9214036b8a15b512e03d534120006
11 | // IV : 0x3dafba429d9eb430b422da802c9fac41
12 | // Plaintext : "Single block msg"
13 | // Ciphertext: 0xe353779c1079aeb82708942dbe77181a
14 | //
15 | // Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with 128-bit key
16 | // Key : 0xc286696d887c9aa0611bbb3e2025a45a
17 | // IV : 0x562e17996d093d28ddb3ba695a2e6f58
18 | // Plaintext : 0x000102030405060708090a0b0c0d0e0f
19 | // 101112131415161718191a1b1c1d1e1f
20 | // Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
21 | // 7586602d253cfff91b8266bea6d61ab1
22 | func main(g, e [16]byte) []byte {
23 | key := []byte{
24 | 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
25 | 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06,
26 | }
27 | iv := []byte{
28 | 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
29 | 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41,
30 | }
31 | plain := []byte("Single block msg")
32 |
33 | key2 := []byte{
34 | 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
35 | 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a,
36 | }
37 | iv2 := []byte{
38 | 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
39 | 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58,
40 | }
41 | plain2 := []byte{
42 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
43 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
44 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
45 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
46 | }
47 |
48 | //return cbc.EncryptAES128(key, iv, plain)
49 | //return cbc.EncryptAES128(key2, iv2, plain2)
50 | return cbc.EncryptAES128(g, iv, e)
51 | }
52 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aesexpand.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/aes"
7 | )
8 |
9 | func main(key, data [16]byte) []uint {
10 | return aes.ExpandEncryptionKey(key)
11 | }
12 |
--------------------------------------------------------------------------------
/apps/garbled/examples/aesgcm.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "bytes"
7 | "crypto/cipher/gcm"
8 | )
9 |
10 | func main(a, b byte) (string, int) {
11 | key := []byte{
12 | 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
13 | 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06,
14 | }
15 | nonce := []byte{
16 | 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
17 | 0xb4, 0x22, 0xda, 0x80,
18 | }
19 | plain := []byte("Single block msgSingle block msg")
20 | additional := []byte("unused")
21 |
22 | cipher := []byte{
23 | 0x95, 0xc9, 0x12, 0xbe, 0x04, 0x22, 0x3b, 0x3f,
24 | 0xdc, 0x60, 0x1b, 0x6f, 0x33, 0x7c, 0xe9, 0x7d,
25 | 0xd9, 0xa6, 0x41, 0x75, 0x3c, 0x99, 0x7e, 0x3e,
26 | 0xcf, 0xdd, 0xc3, 0x92, 0xd2, 0x4b, 0x00, 0xd2,
27 | 0x76, 0x66, 0xc0, 0x99, 0xd7, 0x20, 0xc8, 0x3b,
28 | 0x9a, 0x3c, 0xf6, 0xc9, 0x07, 0x9f, 0xb3, 0x46,
29 | }
30 |
31 | c := gcm.EncryptAES128(key, nonce, plain, additional)
32 | p, ok := gcm.DecryptAES128(key, nonce, c, additional)
33 | if !ok {
34 | return "Open failed", 0
35 | }
36 | return string(p), bytes.Compare(plain, p)
37 | }
38 |
--------------------------------------------------------------------------------
/apps/garbled/examples/and.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b uint1) uint1 {
6 | return a & b
7 | }
8 |
--------------------------------------------------------------------------------
/apps/garbled/examples/bug.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/rsa"
7 | )
8 |
9 | type Size = uint4
10 |
11 | func main(a, b Size) (uint, uint) {
12 | sum := count(a, b)
13 | sum2 := count(b, a)
14 |
15 | return sum, sum2
16 | }
17 |
18 | func count(a, b uint) uint {
19 | sumType := make(uint, size(b))
20 |
21 | var sum sumType
22 |
23 | for i := 0; i < size(a); i++ {
24 | if a>>i&1 == 1 {
25 | sum += b
26 | }
27 | }
28 | return sum
29 | }
30 |
--------------------------------------------------------------------------------
/apps/garbled/examples/call.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b int4) int4 {
6 | return max(a, b)
7 | }
8 |
9 | func max(a, b int4) int4 {
10 | if a > b {
11 | return add1(a)
12 | }
13 | return add1(b)
14 | }
15 |
16 | func min(a, b int4) int4 {
17 | if a < b {
18 | return a
19 | }
20 | return b
21 | }
22 |
23 | func add1(a int4) int4 {
24 | return a + 1
25 | }
26 |
--------------------------------------------------------------------------------
/apps/garbled/examples/call2.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b int) int {
6 | return Sum2(MinMax(a, b))
7 | }
8 |
9 | func Sum2(a, b int) int {
10 | return a + b
11 | }
12 |
13 | func MinMax(a, b int) (int, int) {
14 | if a > b {
15 | return b, a
16 | }
17 | return a, b
18 | }
19 |
--------------------------------------------------------------------------------
/apps/garbled/examples/constant.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | const One = 1
6 | const H0 = 0x5be0cd191f83d9ab9b05688c510e527fa54ff53a3c6ef372bb67ae856a09e667
7 |
8 | func main(a, b uint255) uint255 {
9 | return H0 + a + b + One
10 | }
11 |
--------------------------------------------------------------------------------
/apps/garbled/examples/credit.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Size = uint32
6 |
7 | type Applicant struct {
8 | male bool
9 | age Size
10 | income Size
11 | }
12 |
13 | type Bank struct {
14 | maxAge Size
15 | femaleIncome Size
16 | maleIncome Size
17 | }
18 |
19 | func main(applicant Applicant, bank Bank) bool {
20 | // Bank sets the maximum age limit.
21 | if applicant.age > bank.maxAge {
22 | return false
23 | }
24 | if applicant.male {
25 | // Credit criteria for males.
26 | return applicant.age >= 21 && applicant.income >= bank.maleIncome
27 | } else {
28 | // Credit criteria for females.
29 | return applicant.age >= 18 && applicant.income >= bank.femaleIncome
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/apps/garbled/examples/crypto.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha256"
7 | )
8 |
9 | func main(block1, block2 uint512) uint256 {
10 | return sha256.Block(block1, sha256.H0)
11 | }
12 |
--------------------------------------------------------------------------------
/apps/garbled/examples/div.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | func main(a, b uint8) uint {
7 | return a / b
8 | }
9 |
--------------------------------------------------------------------------------
/apps/garbled/examples/ed25519.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | // This example implements Ed25519 signature computation. The Ed25519
4 | // keypair is:
5 | //
6 | // pub : eeaf1edd378f775a72e6ed706fd30077d3b21595af99898f3cdd0b450482b76f
7 | //
8 | // priv : 189d087817983d5d68c5fae03a74a719b49f4f0a0a82fe83f265c92e88faaa27
9 | // eeaf1edd378f775a72e6ed706fd30077d3b21595af99898f3cdd0b450482b76f
10 | //
11 | // The Garbler and Evaluator share the private key as two random
12 | // shares. The private key is contructed during the signature
13 | // computation by XOR:ing the random shares together:
14 | //
15 | // privG: 5e768ad83640b43d93d6c26b34021d0a0cda6bf5eb962970554d7ab074e2f4cd
16 | // 49bc6fef2fa4dc2f763c1f70b751b7f03d398e8930d837130426454ea52d4449
17 | //
18 | // privE: 46eb82a021d88960fb13388b0e76ba13b84524ffe114d7f3a728b39efc185eea
19 | // a7137132182bab7504daf200d882b787ee8b9b1c9f41be9c38fb4e0ba1aff326
20 | //
21 | // priv = privG ^ privE
22 | //
23 | // Run the Evaluator with one input: the Evaluator's private key share:
24 | //
25 | // $ ./garbled -e -v -stream -i 0x46eb82a021d88960fb13388b0e76ba13b84524ff\
26 | // e114d7f3a728b39efc185eeaa7137132182bab7504daf200d882b787ee8b9b1c9f41be9\
27 | // c38fb4e0ba1aff326
28 | //
29 | // The Garbler takes two inputs: the message to sign, and the
30 | // Garbler's private key share:
31 | //
32 | // $ ./garbled -stream -v -i 0x4d61726b6b7520526f737369203c6d747240696b692\
33 | // e66693e2068747470733a2f2f7777772e6d61726b6b75726f7373692e636f6d2f,\
34 | // 0x5e768ad83640b43d93d6c26b34021d0a0cda6bf5eb962970554d7ab074e2f4cd49bc6\
35 | // fef2fa4dc2f763c1f70b751b7f03d398e8930d837130426454ea52d4449 \
36 | // examples/ed25519.qcl
37 | //
38 | package main
39 |
40 | import (
41 | "crypto/ed25519"
42 | )
43 |
44 | type Garbler struct {
45 | msg [64]byte
46 | privShare [64]byte
47 | }
48 |
49 | func main(g Garbler, privShare [64]byte) []byte {
50 | var priv [64]byte
51 |
52 | for i := 0; i < len(priv); i++ {
53 | priv[i] = g.privShare[i] ^ privShare[i]
54 | }
55 |
56 | return ed25519.Sign(priv, g.msg)
57 | }
58 |
--------------------------------------------------------------------------------
/apps/garbled/examples/ed25519/sign.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | // This example implements Ed25519 signature computation. The Ed25519
4 | // keypair is:
5 | //
6 | // pub : eeaf1edd378f775a72e6ed706fd30077d3b21595af99898f3cdd0b450482b76f
7 | //
8 | // priv : 189d087817983d5d68c5fae03a74a719b49f4f0a0a82fe83f265c92e88faaa27
9 | // eeaf1edd378f775a72e6ed706fd30077d3b21595af99898f3cdd0b450482b76f
10 | //
11 | // The Garbler and Evaluator share the private key as two random
12 | // shares. The private key is contructed during the signature
13 | // computation by XOR:ing the random shares together:
14 | //
15 | // privG: 5e768ad83640b43d93d6c26b34021d0a0cda6bf5eb962970554d7ab074e2f4cd
16 | // 49bc6fef2fa4dc2f763c1f70b751b7f03d398e8930d837130426454ea52d4449
17 | //
18 | // privE: 46eb82a021d88960fb13388b0e76ba13b84524ffe114d7f3a728b39efc185eea
19 | // a7137132182bab7504daf200d882b787ee8b9b1c9f41be9c38fb4e0ba1aff326
20 | //
21 | // priv = privG ^ privE
22 | //
23 | // Run the Evaluator with one input: the Evaluator's private key share:
24 | //
25 | // $ ./garbled -e -v -stream -i 0x46eb82a021d88960fb13388b0e76ba13b84524ffe114d7f3a728b39efc185eeaa7137132182bab7504daf200d882b787ee8b9b1c9f41be9c38fb4e0ba1aff326
26 | //
27 | // The Garbler takes two inputs: the message to sign, and the
28 | // Garbler's private key share:
29 | //
30 | // $ ./garbled -stream -v -i 0x4d61726b6b7520526f737369203c6d747240696b692e66693e2068747470733a2f2f7777772e6d61726b6b75726f7373692e636f6d2f,0x5e768ad83640b43d93d6c26b34021d0a0cda6bf5eb962970554d7ab074e2f4cd49bc6fef2fa4dc2f763c1f70b751b7f03d398e8930d837130426454ea52d4449 examples/ed25519/sign.qcl
31 | //
32 | // The result signature is:
33 | //
34 | // Result[0]: b71a55aece64574bedd94729a9ca95a87b5fe0a587fecf50ff0238805132c1291e08cb871016cb4f3935bd45423626f61dc648a91affda3671b19d7b28e03505
35 | package main
36 |
37 | import (
38 | "crypto/ed25519"
39 | )
40 |
41 | type Garbler struct {
42 | msg [64]byte
43 | privShare [64]byte
44 | }
45 |
46 | func main(g Garbler, privShare [64]byte) []byte {
47 | var priv [64]byte
48 |
49 | for i := 0; i < len(priv); i++ {
50 | priv[i] = g.privShare[i] ^ privShare[i]
51 | }
52 |
53 | return ed25519.Sign(priv, g.msg)
54 | }
55 |
--------------------------------------------------------------------------------
/apps/garbled/examples/encrypt.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | // Run the Evaluator with two inputs: evaluator's key and nonce shares:
4 | //
5 | // $ ./garbled -e -i 0x8cd98b88adab08d6d60fe57c8b8a33f3,0xfd5e0f8f155e7102aa526ad0 examples/encrypt.qcl
6 | //
7 | // The Garbler takes three arguments: the message to encrypt, and its
8 | // key and nonce shares:
9 | //
10 | // $ ./garbled -i 0x48656c6c6f2c20776f726c6421,0xed800b17b0c9d2334b249332155ddef5,0xa300751458c775a08762c2cd examples/encrypt.qcl
11 |
12 | package main
13 |
14 | import (
15 | "crypto/cipher/gcm"
16 | )
17 |
18 | type Garbler struct {
19 | msg [64]byte
20 | keyShare [16]byte
21 | nonceShare [12]byte
22 | }
23 |
24 | type Evaluator struct {
25 | keyShare [16]byte
26 | nonceShare [12]byte
27 | }
28 |
29 | func main(g Garbler, e Evaluator) []byte {
30 | var key [16]byte
31 |
32 | for i := 0; i < len(key); i++ {
33 | key[i] = g.keyShare[i] ^ e.keyShare[i]
34 | }
35 |
36 | var nonce [12]byte
37 |
38 | for i := 0; i < len(nonce); i++ {
39 | nonce[i] = g.nonceShare[i] ^ e.nonceShare[i]
40 | }
41 |
42 | return gcm.EncryptAES128(key, nonce, g.msg, []byte("unused"))
43 | }
44 |
--------------------------------------------------------------------------------
/apps/garbled/examples/hamming.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "encoding/binary"
7 | )
8 |
9 | func main(a, b uint1024) uint {
10 | return binary.HammingDistance(a, b)
11 | }
12 |
--------------------------------------------------------------------------------
/apps/garbled/examples/hmac-sha256.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | // This example computes HMAC-SHA256 where the HMAC key is shared as
4 | // two random shares between garbler and evaluator. The garbler's key
5 | // share is:
6 | //
7 | // keyG: 4de216d2fdc9301e5b9c78486f7109a05670d200d9e2f275ec0aad08ec42af47
8 | // fcb59bf460d50b01333a748f3a9efb13e08036d49a26c21ba2e33a5f8a2cf0e7
9 | //
10 | // The evaluator's key share is:
11 | //
12 | // keyE: f87a00ef89c2396de32f6ac0748f6fa1b641013d46f74ce25cc625904215a675
13 | // 01c0c7196a2602f6516527958a82271847933c35d170d98bfdb04d2ddf3bb197
14 | //
15 | // The final HMAC key is keyG ^ keyE:
16 | //
17 | // key : b598163d740b0973b8b312881bfe6601e031d33d9f15be97b0cc8898ae570932
18 | // fd755ced0af309f7625f531ab01cdc0ba7130ae14b561b905f53777255174170
19 | //
20 | // The example uses 32-byte messages (Garbler.msg) so with the message:
21 | //
22 | // msg : Hello, world!...................
23 | // hex : 48656c6c6f2c20776f726c64212e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e
24 | //
25 | // We expect to get the following HMAC-SHA256 output:
26 | //
27 | // sum : 60d27dbd14f1e351f20069171fead00ef557d17ac9a41d02baa488ca4b90171a
28 | //
29 | // Now we can run the MPC computation as follows. First, run the
30 | // evaluator with one input: the evaluator's key share:
31 | //
32 | // $ ./garbled -e -v -i 0xf87a00ef89c2396de32f6ac0748f6fa1b641013d46f74ce25cc625904215a67501c0c7196a2602f6516527958a82271847933c35d170d98bfdb04d2ddf3bb197 examples/hmac-sha256.qcl
33 | //
34 | // The garbler takes two inputs: the message and the garbler's key
35 | // share:
36 | //
37 | // $ ./garbled -v -i 0x48656c6c6f2c20776f726c64212e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e,0x4de216d2fdc9301e5b9c78486f7109a05670d200d9e2f275ec0aad08ec42af47fcb59bf460d50b01333a748f3a9efb13e08036d49a26c21ba2e33a5f8a2cf0e7 examples/hmac-sha256.qcl
38 | //
39 | // The MCP computation providers the expected HMAC result:
40 | //
41 | // Result[0]: 60d27dbd14f1e351f20069171fead00ef557d17ac9a41d02baa488ca4b90171a
42 |
43 | package main
44 |
45 | import (
46 | "crypto/hmac"
47 | )
48 |
49 | type Garbler struct {
50 | msg []byte
51 | keyShare [64]byte
52 | }
53 |
54 | func main(g Garbler, eKeyShare [64]byte) []byte {
55 | var key [64]byte
56 |
57 | for i := 0; i < len(key); i++ {
58 | key[i] = g.keyShare[i] ^ eKeyShare[i]
59 | }
60 |
61 | return hmac.SumSHA256(g.msg, key)
62 | }
63 |
--------------------------------------------------------------------------------
/apps/garbled/examples/hmac.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/hmac"
7 | )
8 |
9 | // HMAC-SHA256 tests:
10 | //
11 | // "abc", "message": 859cc656e12c0ecd0afdd7e3d034c3ee81609fcac1b454c231211c7ac69895e8
12 | func main(g, e byte) []byte {
13 | return hmac.SumSHA256([]byte("message"), []byte("abc"))
14 | }
15 |
--------------------------------------------------------------------------------
/apps/garbled/examples/max.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b int4) int4 {
6 | if a > b {
7 | return a
8 | }
9 | return b
10 | }
11 |
--------------------------------------------------------------------------------
/apps/garbled/examples/max3.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | type Size = int4
7 |
8 | type G struct {
9 | a, b Size
10 | }
11 |
12 | func main(g G, e Size) int {
13 | if g.a > g.b {
14 | if g.a > e {
15 | return g.a
16 | } else {
17 | return e
18 | }
19 | } else {
20 | if g.b > e {
21 | return g.b
22 | } else {
23 | return e
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/apps/garbled/examples/millionaire.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | func main(a, b int64) bool {
7 | if a > b {
8 | return true
9 | } else {
10 | return false
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/apps/garbled/examples/montgomery.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | import (
7 | "math"
8 | )
9 |
10 | // $ ./garbled -e -v -i 0x321af130 examples/montgomery.qcl
11 | // $ ./garbled -v -i 0x6d7472,9,0xd60b2b09,0x10001 examples/montgomery.qcl
12 |
13 | type Size = uint64
14 |
15 | type Garbler struct {
16 | msg Size
17 | privShare Size
18 | pubN Size
19 | pubE Size
20 | }
21 |
22 | func main(g Garbler, privShare Size) (uint, uint) {
23 |
24 | priv := g.privShare + privShare
25 |
26 | cipher := Encrypt(g.msg, g.pubE, g.pubN)
27 | plain := Decrypt(cipher, priv, g.pubN)
28 |
29 | return cipher, plain
30 | }
31 |
32 | func Encrypt(msg, e, n uint) uint {
33 | return math.ExpMontgomery(msg, e, n)
34 | }
35 |
36 | func Decrypt(cipher, d, n uint) uint {
37 | return math.ExpMontgomery(cipher, d, n)
38 | }
39 |
--------------------------------------------------------------------------------
/apps/garbled/examples/mult.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | func main(a, b uint64) uint {
7 | return a * b
8 | }
9 |
--------------------------------------------------------------------------------
/apps/garbled/examples/mult1024.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | func main(a, b int1024) int1024 {
7 | return a * b
8 | }
9 |
--------------------------------------------------------------------------------
/apps/garbled/examples/nc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func main(a, b int8) int8 {
6 | return a + b
7 | }
8 |
--------------------------------------------------------------------------------
/apps/garbled/examples/parametrized-main.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Garbler struct {
6 | a []byte
7 | b []byte
8 | }
9 |
10 | func main(g Garbler, e []byte) (int, []byte) {
11 | l := len(g.b)
12 | if len(e) < l {
13 | l = len(e)
14 | }
15 | result := make([]byte, l)
16 |
17 | for i := 0; i < l; i++ {
18 | result[i] = g.b[i] ^ e[i]
19 | }
20 | return l, result
21 | }
22 |
--------------------------------------------------------------------------------
/apps/garbled/examples/pkg.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "math"
7 | )
8 |
9 | const MaxUint64 = 42
10 |
11 | // @Test 0 0 = 42 0xffffffffffffffff
12 | func main(a, b uint64) (uint64, uint64) {
13 | return MaxUint64, math.MaxUint64
14 | }
15 |
--------------------------------------------------------------------------------
/apps/garbled/examples/ptr.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // func add(arr []int32, inc int32) []int32 {
6 | // result := make([]int32, len(arr))
7 | // copy(result, arr)
8 | //
9 | // for i := 0; i < len(arr); i++ {
10 | // result[i] += inc
11 | // }
12 | // return result
13 | // }
14 |
15 | // @Test 0 0 = 49
16 | // @Test 1 2 = 52
17 | func main(a, b int32) []int32 {
18 | //arr := make([]int32, 10)
19 | //for i := 0; i < 10; i++ {
20 | //arr[i] = a
21 | //}
22 |
23 | result := make([]int32, 10)
24 |
25 | //var result [10]int32
26 | //copy(result, arr)
27 |
28 | return result
29 |
30 | //return add(arr, b)
31 | }
32 |
--------------------------------------------------------------------------------
/apps/garbled/examples/rps.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Rock, Paper, Scissors
4 |
5 | package main
6 |
7 | func main(g, e int8) string {
8 | if g == e {
9 | return "-"
10 | }
11 | if (g+1)%3 == e {
12 | return "evaluator"
13 | }
14 | return "garbler"
15 | }
16 |
--------------------------------------------------------------------------------
/apps/garbled/examples/rsa.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | import (
7 | "crypto/rsa"
8 | )
9 |
10 | // d: 0x321af139
11 | // n: 0xd60b2b09
12 | // e: 0x10001
13 | //
14 | // private: d, n
15 | // public: e, n
16 |
17 | // msg: 0x6d7472
18 | // cipher: 0x61f9ef88
19 |
20 | // $ ./garbled -e -v -i 9 examples/rsa.qcl
21 | // $ ./garbled -v -i 0x6d7472,0x321af130,0xd60b2b09,0x10001 examples/rsa.qcl
22 |
23 | type Size = uint32
24 |
25 | type Garbler struct {
26 | msg Size
27 | privShare Size
28 | pubN Size
29 | pubE Size
30 | }
31 |
32 | func main(g Garbler, privShare Size) (uint, uint) {
33 |
34 | priv := g.privShare + privShare
35 |
36 | cipher := rsa.Encrypt(g.msg, g.pubE, g.pubN)
37 | plain := rsa.Decrypt(cipher, priv, g.pubN)
38 |
39 | return cipher, plain
40 | }
41 |
--------------------------------------------------------------------------------
/apps/garbled/examples/rsasign.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | import (
7 | "crypto/rsa"
8 | )
9 |
10 | // d: 0x321af139
11 | // n: 0xd60b2b09
12 | // e: 0x10001
13 | //
14 | // private: d, n
15 | // public: e, n
16 |
17 | // msg: 0x6d7472
18 | // signature: 0x55a83b79
19 |
20 | // ./garbled -e -v -i 9 examples/rsasign.qcl
21 | // ./garbled -v -i 0x6d7472,0x321af130,0xd60b2b09,0x10001 examples/rsasign.qcl
22 |
23 | type Size = uint512
24 |
25 | type Garbler struct {
26 | msg Size
27 | privShare Size
28 | pubN Size
29 | pubE Size
30 | }
31 |
32 | func main(g Garbler, privShare Size) uint {
33 |
34 | priv := g.privShare + privShare
35 |
36 | return rsa.Decrypt(g.msg, priv, g.pubN)
37 | }
38 |
--------------------------------------------------------------------------------
/apps/garbled/examples/sha256.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha256"
7 | )
8 |
9 | // Tests:
10 | // "": e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
11 | // "a": ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
12 | // "m": 62c66a7a5dd70c3146618063c344e531e6d4b59e379808443ce962b3abd63c5a
13 | // "t": e3b98a4da31a127d4bde6e43033f66ba274cab0eb7eb1c70ec41402bf6273dd8
14 | // "mt": fe7f7ccc3fc17be1d0804567821a101836b66dd8eb03ed7604872285e013f771
15 | // "mtr": a39d3ae3da34f2b4c01193e62202d5de0db79f800a039624b0f950734782b863
16 | func main(g, e byte) []byte {
17 | return sha256.Sum256([]byte("mtr"))
18 | }
19 |
--------------------------------------------------------------------------------
/apps/garbled/examples/sha512.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha512"
7 | )
8 |
9 | // Tests:
10 | //
11 | // "": cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce
12 | // 47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
13 | //
14 | // "m": f14aae6a0e050b74e4b7b9a5b2ef1a60ceccbbca39b132ae3e8bf88d3a946c6d
15 | // 8687f3266fd2b626419d8b67dcf1d8d7c0fe72d4919d9bd05efbd37070cfb41a
16 | //
17 | // "mt": 34fbeb80899199a7c2f7e21c116895f7bc465848d896bafdeb20b7be50c06c79
18 | // 40800e51d6f0870deb4bb99a00787b074df04e6f4edb351b3b187e9d3c7ad3b3
19 | //
20 | // "mtr": b1abf7ba69e9cbda84337104b2a69d30473388c2146aa9ef85ac9dab3cca6172
21 | // 6d7bef26793294587f7e835fcf0d031a35f027199fba78e1282dea16091c6fd1
22 |
23 | func main(g, e byte) []byte {
24 | var data [3]byte
25 |
26 | data[0] = 0x6d
27 | data[1] = 0x74
28 | data[2] = 0x72
29 |
30 | return sha512.Sum512(data[:])
31 | }
32 |
--------------------------------------------------------------------------------
/apps/garbled/examples/sort.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "sort"
7 | )
8 |
9 | var input = []int9{
10 | 136, 142,
11 | 146, 165, 183, 189, 220, 223, 232, 235,
12 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
13 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
14 | 245, 249, 252,
15 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
16 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
17 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
18 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
19 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
20 | 245, 249, 252,
21 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
22 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
23 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
24 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
25 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
26 | 245, 249, 252,
27 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
28 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
29 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
30 | 245, 249, 252,
31 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
32 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
33 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
34 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
35 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
36 | 245, 249, 252,
37 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
38 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
39 | 136, 142, 146, 165, 183, 189, 220, 223, 232, 235,
40 | 67, 73, 77, 88, 91, 93, 95, 97, 98, 132,
41 | 5, 6, 7, 10, 14, 18, 18, 37, 50, 64,
42 | 245, 249, 252,
43 | }
44 |
45 | func main(g, e byte) []int {
46 | return sort.Reverse(sort.Slice(input))
47 | }
48 |
--------------------------------------------------------------------------------
/apps/garbled/result.go:
--------------------------------------------------------------------------------
1 | //
2 | // main.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package main
10 |
11 | import (
12 | "fmt"
13 | "math/big"
14 | "unicode"
15 |
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
17 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
18 | )
19 |
20 | func printResults(results []*big.Int, outputs circuit.IO) {
21 | for idx, result := range results {
22 | if outputs == nil {
23 | fmt.Printf("Result[%d]: %v\n", idx, result)
24 | fmt.Printf("Result[%d]: 0b%s\n", idx, result.Text(2))
25 | bytes := result.Bytes()
26 | if len(bytes) == 0 {
27 | bytes = []byte{0}
28 | }
29 | fmt.Printf("Result[%d]: 0x%x\n", idx, bytes)
30 | } else {
31 | fmt.Printf("Result[%d]: %s\n", idx,
32 | printResult(result, outputs[idx], false))
33 | }
34 | }
35 | }
36 |
37 | func printResult(result *big.Int, output circuit.IOArg, short bool) string {
38 | var str string
39 |
40 | switch output.Type.Type {
41 | case types.TString:
42 | mask := big.NewInt(0xff)
43 |
44 | for i := 0; i < int(output.Type.Bits)/8; i++ {
45 | tmp := new(big.Int).Rsh(result, uint(i*8))
46 | r := rune(tmp.And(tmp, mask).Uint64())
47 | if unicode.IsPrint(r) {
48 | str += string(r)
49 | } else {
50 | str += fmt.Sprintf("\\u%04x", r)
51 | }
52 | }
53 |
54 | case types.TUint, types.TInt:
55 | if output.Type.Type == types.TInt {
56 | bits := int(output.Type.Bits)
57 | if result.Bit(bits-1) == 1 {
58 | // Negative number.
59 | tmp := new(big.Int)
60 | tmp.SetBit(tmp, bits, 1)
61 | result.Sub(tmp, result)
62 | result.Neg(result)
63 | }
64 | }
65 |
66 | bytes := result.Bytes()
67 | if len(bytes) == 0 {
68 | bytes = []byte{0}
69 | }
70 | if short {
71 | str = fmt.Sprintf("%v", result)
72 | } else if output.Type.Bits <= 64 {
73 | str = fmt.Sprintf("0x%x\t%v", bytes, result)
74 | } else {
75 | str = fmt.Sprintf("0x%x", bytes)
76 | }
77 |
78 | case types.TBool:
79 | str = fmt.Sprintf("%v", result.Uint64() != 0)
80 |
81 | case types.TArray:
82 | count := int(output.Type.ArraySize)
83 | elSize := int(output.Type.ElementType.Bits)
84 |
85 | mask := new(big.Int)
86 | for i := 0; i < elSize; i++ {
87 | mask.SetBit(mask, i, 1)
88 | }
89 |
90 | var hexString bool
91 | if output.Type.ElementType.Type == types.TUint &&
92 | output.Type.ElementType.Bits == 8 {
93 | hexString = true
94 | }
95 | if !hexString {
96 | str = "["
97 | }
98 | for i := 0; i < count; i++ {
99 | r := new(big.Int).Rsh(result, uint(i*elSize))
100 | r = r.And(r, mask)
101 |
102 | if hexString {
103 | str += fmt.Sprintf("%02x", r.Int64())
104 | } else {
105 | if i > 0 {
106 | str += " "
107 | }
108 | str += printResult(r, circuit.IOArg{
109 | Type: *output.Type.ElementType,
110 | }, true)
111 | }
112 | }
113 | if !hexString {
114 | str += "]"
115 | }
116 |
117 | default:
118 | str = fmt.Sprintf("%v (%s)", result, output.Type)
119 | }
120 |
121 | return str
122 | }
123 |
--------------------------------------------------------------------------------
/apps/garbled/streaming.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package main
8 |
9 | import (
10 | "fmt"
11 | "io"
12 | "net"
13 | "strings"
14 |
15 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler"
17 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
18 | "source.quilibrium.com/quilibrium/monorepo/bedlam/ot"
19 | "source.quilibrium.com/quilibrium/monorepo/bedlam/p2p"
20 | )
21 |
22 | func streamEvaluatorMode(oti ot.OT, input input, once bool) error {
23 | inputSizes, err := circuit.InputSizes(input)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | ln, err := net.Listen("tcp", port)
29 | if err != nil {
30 | return err
31 | }
32 | fmt.Printf("Listening for connections at %s\n", port)
33 |
34 | for {
35 | nc, err := ln.Accept()
36 | if err != nil {
37 | return err
38 | }
39 | fmt.Printf("New connection from %s\n", nc.RemoteAddr())
40 |
41 | conn := p2p.NewConn(nc)
42 |
43 | err = conn.SendInputSizes(inputSizes)
44 | if err != nil {
45 | conn.Close()
46 | return err
47 | }
48 | err = conn.Flush()
49 | if err != nil {
50 | conn.Close()
51 | return err
52 | }
53 |
54 | outputs, result, err := circuit.StreamEvaluator(conn, oti, input,
55 | verbose)
56 | conn.Close()
57 |
58 | if err != nil && err != io.EOF {
59 | return err
60 | }
61 |
62 | printResults(result, outputs)
63 | if once {
64 | return nil
65 | }
66 | }
67 | }
68 |
69 | func streamGarblerMode(params *utils.Params, oti ot.OT, input input,
70 | args []string) error {
71 |
72 | inputSizes := make([][]int, 2)
73 |
74 | sizes, err := circuit.InputSizes(input)
75 | if err != nil {
76 | return err
77 | }
78 | inputSizes[0] = sizes
79 |
80 | if len(args) != 1 || !strings.HasSuffix(args[0], ".qcl") {
81 | return fmt.Errorf("streaming mode takes single QCL file")
82 | }
83 | nc, err := net.Dial("tcp", port)
84 | if err != nil {
85 | return err
86 | }
87 | conn := p2p.NewConn(nc)
88 | defer conn.Close()
89 |
90 | sizes, err = conn.ReceiveInputSizes()
91 | if err != nil {
92 | return err
93 | }
94 | inputSizes[1] = sizes
95 |
96 | outputs, result, err := compiler.New(params).StreamFile(
97 | conn, oti, args[0], input, inputSizes)
98 | if err != nil {
99 | return err
100 | }
101 | printResults(result, outputs)
102 | return nil
103 | }
104 |
--------------------------------------------------------------------------------
/apps/iotest/iotest.go:
--------------------------------------------------------------------------------
1 | //
2 | // main.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package main
10 |
11 | import (
12 | "fmt"
13 | "io"
14 | "net"
15 |
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
17 | "source.quilibrium.com/quilibrium/monorepo/bedlam/ot"
18 | "source.quilibrium.com/quilibrium/monorepo/bedlam/p2p"
19 | )
20 |
21 | func evaluatorTestIO(size int64, once bool) error {
22 | ln, err := net.Listen("tcp", port)
23 | if err != nil {
24 | return err
25 | }
26 | fmt.Printf("Listening for connections at %s\n", port)
27 |
28 | for {
29 | nc, err := ln.Accept()
30 | if err != nil {
31 | return err
32 | }
33 | fmt.Printf("New connection from %s\n", nc.RemoteAddr())
34 |
35 | conn := p2p.NewConn(nc)
36 | for {
37 | var label ot.Label
38 | var labelData ot.LabelData
39 | err = conn.ReceiveLabel(&label, &labelData)
40 | if err != nil {
41 | if err == io.EOF {
42 | break
43 | }
44 | return err
45 | }
46 | }
47 | fmt.Printf("Received: %v\n",
48 | circuit.FileSize(conn.Stats.Sum()).String())
49 |
50 | if once {
51 | return nil
52 | }
53 | }
54 | }
55 |
56 | func garblerTestIO(size int64) error {
57 | nc, err := net.Dial("tcp", port)
58 | if err != nil {
59 | return err
60 | }
61 | conn := p2p.NewConn(nc)
62 |
63 | var sent int64
64 | var label ot.Label
65 | var labelData ot.LabelData
66 |
67 | for sent < size {
68 | err = conn.SendLabel(label, &labelData)
69 | if err != nil {
70 | return err
71 | }
72 | sent += int64(len(labelData))
73 | }
74 | if err := conn.Flush(); err != nil {
75 | return err
76 | }
77 | if err := conn.Close(); err != nil {
78 | return err
79 | }
80 |
81 | fmt.Printf("Sent: %v\n", circuit.FileSize(conn.Stats.Sum()).String())
82 | return nil
83 | }
84 |
--------------------------------------------------------------------------------
/apps/iotest/main.go:
--------------------------------------------------------------------------------
1 | //
2 | // main.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package main
10 |
11 | import (
12 | "flag"
13 | "log"
14 | "os"
15 | "runtime/pprof"
16 | )
17 |
18 | var (
19 | port = ":8080"
20 | )
21 |
22 | func main() {
23 | evaluator := flag.Bool("e", false, "evaluator / garbler mode")
24 | cpuprofile := flag.String("cpuprofile", "", "write cpu profile to `file`")
25 | testIO := flag.Int64("test-io", 0, "test I/O performance")
26 | flag.Parse()
27 |
28 | log.SetFlags(0)
29 |
30 | if len(*cpuprofile) > 0 {
31 | f, err := os.Create(*cpuprofile)
32 | if err != nil {
33 | log.Fatal("could not create CPU profile: ", err)
34 | }
35 | defer f.Close()
36 | if err := pprof.StartCPUProfile(f); err != nil {
37 | log.Fatal("could not start CPU profile: ", err)
38 | }
39 | defer pprof.StopCPUProfile()
40 | }
41 |
42 | if *testIO > 0 {
43 | if *evaluator {
44 | err := evaluatorTestIO(*testIO, len(*cpuprofile) > 0)
45 | if err != nil {
46 | log.Fatal(err)
47 | }
48 | } else {
49 | err := garblerTestIO(*testIO)
50 | if err != nil {
51 | log.Fatal(err)
52 | }
53 | }
54 | return
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/circuit/aesni/.gitignore:
--------------------------------------------------------------------------------
1 | c/aesni
2 |
--------------------------------------------------------------------------------
/circuit/aesni/GNUmakefile:
--------------------------------------------------------------------------------
1 |
2 | all: benchmarks
3 |
4 | benchmarks: c/aesni
5 | go test -bench=.
6 | c/aesni
7 |
8 | c/aesni: c/aesni.c
9 | gcc -Wall -maes -march=native -o $@ $+
10 |
--------------------------------------------------------------------------------
/circuit/aesni/go_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // enc_test.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package aesni
10 |
11 | import (
12 | "crypto/aes"
13 | "crypto/cipher"
14 | "crypto/rand"
15 | "encoding/binary"
16 | "io"
17 | "testing"
18 | )
19 |
20 | type LabelX struct {
21 | d0 uint64
22 | d1 uint64
23 | }
24 |
25 | func NewLabelX(rand io.Reader) (LabelX, error) {
26 | var buf [16]byte
27 | var result LabelX
28 |
29 | _, err := rand.Read(buf[:])
30 | if err != nil {
31 | return result, err
32 | }
33 | result.SetData(&buf)
34 |
35 | return result, nil
36 | }
37 |
38 | func (l *LabelX) SetData(buf *[16]byte) {
39 | l.d0 = binary.BigEndian.Uint64((*buf)[0:8])
40 | l.d1 = binary.BigEndian.Uint64((*buf)[8:16])
41 | }
42 |
43 | func (l *LabelX) GetData(buf *[16]byte) {
44 | binary.BigEndian.PutUint64((*buf)[0:8], l.d0)
45 | binary.BigEndian.PutUint64((*buf)[8:16], l.d1)
46 | }
47 |
48 | func (l *LabelX) Xor(o LabelX) {
49 | l.d0 ^= o.d0
50 | l.d1 ^= o.d1
51 | }
52 |
53 | func (l *LabelX) Mul2() {
54 | l.d0 <<= 1
55 | l.d0 |= (l.d1 >> 63)
56 | l.d1 <<= 1
57 | }
58 |
59 | func (l *LabelX) Mul4() {
60 | l.d0 <<= 2
61 | l.d0 |= (l.d1 >> 62)
62 | l.d1 <<= 2
63 | }
64 |
65 | func TestLabelXor(t *testing.T) {
66 | val := uint64(0b0101010101010101010101010101010101010101010101010101010101010101)
67 | a := LabelX{
68 | d0: val,
69 | d1: val << 1,
70 | }
71 | b := LabelX{
72 | d0: 0xffffffffffffffff,
73 | d1: 0xffffffffffffffff,
74 | }
75 | a.Xor(b)
76 | if a.d0 != val<<1 {
77 | t.Errorf("Xor: unexpected d0=%x, epected %x", a.d0, val<<1)
78 | }
79 | if a.d1 != val {
80 | t.Errorf("Xor: unexpected d1=%x, epected %x", a.d1, val)
81 | }
82 | }
83 |
84 | func NewTweakX(tweak uint32) LabelX {
85 | return LabelX{
86 | d1: uint64(tweak),
87 | }
88 | }
89 |
90 | func encryptX(alg cipher.Block, a, b, c LabelX, t uint32,
91 | buf *[16]byte) LabelX {
92 |
93 | k := makeKX(a, b, t)
94 |
95 | k.GetData(buf)
96 | alg.Encrypt(buf[:], buf[:])
97 |
98 | var pi LabelX
99 | pi.SetData(buf)
100 |
101 | pi.Xor(k)
102 | pi.Xor(c)
103 |
104 | return pi
105 | }
106 |
107 | func makeKX(a, b LabelX, t uint32) LabelX {
108 | a.Mul2()
109 |
110 | b.Mul4()
111 | a.Xor(b)
112 |
113 | a.Xor(NewTweakX(t))
114 |
115 | return a
116 | }
117 |
118 | func BenchmarkLabelX(b *testing.B) {
119 | var key [32]byte
120 |
121 | cipher, err := aes.NewCipher(key[:])
122 | if err != nil {
123 | b.Fatalf("Failed to create cipher: %s", err)
124 | }
125 |
126 | al, err := NewLabelX(rand.Reader)
127 | if err != nil {
128 | b.Fatalf("Failed to create label: %s", err)
129 | }
130 | bl, err := NewLabelX(rand.Reader)
131 | if err != nil {
132 | b.Fatalf("Failed to create label: %s", err)
133 | }
134 | cl, err := NewLabelX(rand.Reader)
135 | if err != nil {
136 | b.Fatalf("Failed to create label: %s", err)
137 | }
138 |
139 | b.ResetTimer()
140 | var buf [16]byte
141 | for i := 0; i < b.N; i++ {
142 | encryptX(cipher, al, bl, cl, uint32(i), &buf)
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/circuit/analyze.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2021 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "fmt"
11 | )
12 |
13 | // Analyze identifies potential optimizations for the circuit.
14 | func (c *Circuit) Analyze() {
15 | fmt.Printf("analyzing circuit %v\n", c)
16 |
17 | from := make([][]Gate, c.NumWires)
18 | to := make([][]Gate, c.NumWires)
19 |
20 | // Collect wire inputs and outputs.
21 | for _, g := range c.Gates {
22 | switch g.Op {
23 | case XOR, XNOR, AND, OR:
24 | to[g.Input1] = append(to[g.Input1], g)
25 | fallthrough
26 |
27 | case INV:
28 | to[g.Input0] = append(to[g.Input0], g)
29 | from[g.Output] = append(to[g.Output], g)
30 | }
31 | }
32 |
33 | // INV gates as single output of input gate.
34 | for _, g := range c.Gates {
35 | if g.Op != INV {
36 | continue
37 | }
38 | if len(to[g.Input0]) == 1 && len(from[g.Input0]) == 1 {
39 | fmt.Printf("%v -> %v\n", from[g.Input0][0].Op, g.Op)
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/circuit/circuit_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2022-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "testing"
11 | "unsafe"
12 | )
13 |
14 | func TestSize(t *testing.T) {
15 | var g Gate
16 | if unsafe.Sizeof(g) != 20 {
17 | t.Errorf("unexpected gate size: got %v, expected 20", unsafe.Sizeof(g))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/circuit/computer.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "fmt"
11 | "math/big"
12 | )
13 |
14 | // Compute evaluates the circuit with the given input values.
15 | func (c *Circuit) Compute(inputs []*big.Int) ([]*big.Int, error) {
16 | // Flatten circuit arguments.
17 | var args IO
18 | for _, io := range c.Inputs {
19 | if len(io.Compound) > 0 {
20 | args = append(args, io.Compound...)
21 | } else {
22 | args = append(args, io)
23 | }
24 | }
25 | if len(inputs) != len(args) {
26 | return nil, fmt.Errorf("invalid inputs: got %d, expected %d",
27 | len(inputs), len(args))
28 | }
29 |
30 | // Flatten inputs and arguments.
31 | wires := make([]byte, c.NumWires)
32 |
33 | var w int
34 | for idx, io := range args {
35 | for bit := 0; bit < int(io.Type.Bits); bit++ {
36 | wires[w] = byte(inputs[idx].Bit(bit))
37 | w++
38 | }
39 | }
40 |
41 | // Evaluate circuit.
42 | for _, gate := range c.Gates {
43 | var result byte
44 |
45 | switch gate.Op {
46 | case XOR:
47 | result = wires[gate.Input0] ^ wires[gate.Input1]
48 |
49 | case XNOR:
50 | if wires[gate.Input0]^wires[gate.Input1] == 0 {
51 | result = 1
52 | } else {
53 | result = 0
54 | }
55 |
56 | case AND:
57 | result = wires[gate.Input0] & wires[gate.Input1]
58 |
59 | case OR:
60 | result = wires[gate.Input0] | wires[gate.Input1]
61 |
62 | case INV:
63 | if wires[gate.Input0] == 0 {
64 | result = 1
65 | } else {
66 | result = 0
67 | }
68 |
69 | default:
70 | return nil, fmt.Errorf("invalid gate %s", gate.Op)
71 | }
72 |
73 | wires[gate.Output] = result
74 | }
75 |
76 | // Construct outputs
77 | w = c.NumWires - c.Outputs.Size()
78 | var result []*big.Int
79 | for _, io := range c.Outputs {
80 | r := new(big.Int)
81 | for bit := 0; bit < int(io.Type.Bits); bit++ {
82 | if wires[w] != 0 {
83 | r.SetBit(r, bit, 1)
84 | }
85 | w++
86 | }
87 | result = append(result, r)
88 | }
89 |
90 | return result, nil
91 | }
92 |
--------------------------------------------------------------------------------
/circuit/dot.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "fmt"
11 | "io"
12 | )
13 |
14 | // Dot creates graphviz dot output of the circuit.
15 | func (c *Circuit) Dot(out io.Writer) {
16 | fmt.Fprintf(out, "digraph circuit\n{\n")
17 | fmt.Fprintf(out, " overlap=scale;\n")
18 | fmt.Fprintf(out, " node\t[fontname=\"Helvetica\"];\n")
19 | fmt.Fprintf(out, " {\n node [shape=plaintext];\n")
20 | for w := 0; w < c.NumWires; w++ {
21 | fmt.Fprintf(out, " w%d\t[label=\"%d\"];\n", w, w)
22 | }
23 | fmt.Fprintf(out, " }\n")
24 |
25 | fmt.Fprintf(out, " {\n node [shape=box];\n")
26 | for idx, gate := range c.Gates {
27 | fmt.Fprintf(out, " g%d\t[label=\"%s\"];\n", idx, gate.Op)
28 | }
29 | fmt.Fprintf(out, " }\n")
30 |
31 | if true {
32 | fmt.Fprintf(out, " { rank=same")
33 | var numInputs int
34 | for _, input := range c.Inputs {
35 | numInputs += int(input.Type.Bits)
36 | }
37 | for w := 0; w < numInputs; w++ {
38 | fmt.Fprintf(out, "; w%d", w)
39 | }
40 | fmt.Fprintf(out, ";}\n")
41 |
42 | fmt.Fprintf(out, " { rank=same")
43 | for w := 0; w < c.Outputs.Size(); w++ {
44 | fmt.Fprintf(out, "; w%d", c.NumWires-w-1)
45 | }
46 | fmt.Fprintf(out, ";}\n")
47 | }
48 |
49 | for idx, gate := range c.Gates {
50 | for _, i := range gate.Inputs() {
51 | fmt.Fprintf(out, " w%d -> g%d;\n", i, idx)
52 | }
53 | fmt.Fprintf(out, " g%d -> w%d;\n", idx, gate.Output)
54 | }
55 | fmt.Fprintf(out, "}\n")
56 | }
57 |
--------------------------------------------------------------------------------
/circuit/enc_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // enc_test.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuit
10 |
11 | import (
12 | "crypto/aes"
13 | "crypto/rand"
14 | "testing"
15 |
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/ot"
17 | )
18 |
19 | func TestEnc(t *testing.T) {
20 | a, _ := ot.NewLabel(rand.Reader)
21 | b, _ := ot.NewLabel(rand.Reader)
22 | c, _ := ot.NewLabel(rand.Reader)
23 | tweak := uint32(42)
24 | var key [32]byte
25 |
26 | cipher, err := aes.NewCipher(key[:])
27 | if err != nil {
28 | t.Fatalf("Failed to create cipher: %s", err)
29 | }
30 |
31 | var data ot.LabelData
32 |
33 | encrypted := encrypt(cipher, a, b, c, tweak, &data)
34 | if err != nil {
35 | t.Fatalf("Encrypt failed: %s", err)
36 | }
37 |
38 | plain := decrypt(cipher, a, b, tweak, encrypted, &data)
39 |
40 | if !c.Equal(plain) {
41 | t.Fatalf("Encrypt-decrypt failed")
42 | }
43 | }
44 |
45 | func BenchmarkEnc(b *testing.B) {
46 | var key [32]byte
47 |
48 | cipher, err := aes.NewCipher(key[:])
49 | if err != nil {
50 | b.Fatalf("Failed to create cipher: %s", err)
51 | }
52 |
53 | al, err := ot.NewLabel(rand.Reader)
54 | if err != nil {
55 | b.Fatalf("Failed to create label: %s", err)
56 | }
57 | bl, err := ot.NewLabel(rand.Reader)
58 | if err != nil {
59 | b.Fatalf("Failed to create label: %s", err)
60 | }
61 | cl, err := ot.NewLabel(rand.Reader)
62 | if err != nil {
63 | b.Fatalf("Failed to create label: %s", err)
64 | }
65 |
66 | b.ResetTimer()
67 | var data ot.LabelData
68 | for i := 0; i < b.N; i++ {
69 | encrypt(cipher, al, bl, cl, uint32(i), &data)
70 | }
71 | }
72 |
73 | func BenchmarkEncHalf(b *testing.B) {
74 | var key [32]byte
75 |
76 | cipher, err := aes.NewCipher(key[:])
77 | if err != nil {
78 | b.Fatalf("Failed to create cipher: %s", err)
79 | }
80 |
81 | xl, err := ot.NewLabel(rand.Reader)
82 | if err != nil {
83 | b.Fatalf("Failed to create label: %s", err)
84 | }
85 |
86 | b.ResetTimer()
87 | var data ot.LabelData
88 | for i := 0; i < b.N; i++ {
89 | encryptHalf(cipher, xl, uint32(i), &data)
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/circuit/eval.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019-2021 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "crypto/aes"
11 | "fmt"
12 |
13 | "source.quilibrium.com/quilibrium/monorepo/bedlam/ot"
14 | )
15 |
16 | // Eval evaluates the circuit.
17 | func (c *Circuit) Eval(key []byte, wires []ot.Label,
18 | garbled [][]ot.Label) error {
19 |
20 | alg, err := aes.NewCipher(key)
21 | if err != nil {
22 | return err
23 | }
24 |
25 | var data ot.LabelData
26 | var id uint32
27 |
28 | for i := 0; i < len(c.Gates); i++ {
29 | gate := &c.Gates[i]
30 |
31 | var a, b, c ot.Label
32 |
33 | switch gate.Op {
34 | case XOR, XNOR, AND, OR:
35 | a = wires[gate.Input0]
36 | b = wires[gate.Input1]
37 |
38 | case INV:
39 | a = wires[gate.Input0]
40 |
41 | default:
42 | return fmt.Errorf("invalid operation %s", gate.Op)
43 | }
44 |
45 | var output ot.Label
46 |
47 | switch gate.Op {
48 | case XOR, XNOR:
49 | a.Xor(b)
50 | output = a
51 |
52 | case AND:
53 | row := garbled[i]
54 | if len(row) != 2 {
55 | return fmt.Errorf("corrupted ciruit: AND row length: %d",
56 | len(row))
57 | }
58 | sa := a.S()
59 | sb := b.S()
60 |
61 | j0 := id
62 | j1 := id + 1
63 | id += 2
64 |
65 | tg := row[0]
66 | te := row[1]
67 |
68 | wg := encryptHalf(alg, a, j0, &data)
69 | if sa {
70 | wg.Xor(tg)
71 | }
72 | we := encryptHalf(alg, b, j1, &data)
73 | if sb {
74 | we.Xor(te)
75 | we.Xor(a)
76 | }
77 | output = wg
78 | output.Xor(we)
79 |
80 | case OR:
81 | row := garbled[i]
82 | index := idx(a, b)
83 | if index > 0 {
84 | // First row is zero and not transmitted.
85 | index--
86 | if index >= len(row) {
87 | return fmt.Errorf("corrupted circuit: index %d >= row %d",
88 | index, len(row))
89 | }
90 | c = row[index]
91 | }
92 |
93 | output = decrypt(alg, a, b, id, c, &data)
94 | id++
95 |
96 | case INV:
97 | row := garbled[i]
98 | index := idxUnary(a)
99 | if index > 0 {
100 | // First row is zero and not transmitted.
101 | index--
102 | if index >= len(row) {
103 | return fmt.Errorf("corrupted circuit: index %d >= row %d",
104 | index, len(row))
105 | }
106 | c = row[index]
107 | }
108 | output = decrypt(alg, a, ot.Label{}, id, c, &data)
109 | id++
110 | }
111 | wires[gate.Output] = output
112 | }
113 |
114 | return nil
115 | }
116 |
--------------------------------------------------------------------------------
/circuit/ioarg.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "fmt"
11 | "math/big"
12 | "strings"
13 |
14 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
15 | )
16 |
17 | // IOArg describes circuit input argument.
18 | type IOArg struct {
19 | Name string
20 | Type types.Info
21 | Compound IO
22 | }
23 |
24 | func (io IOArg) String() string {
25 | if len(io.Compound) > 0 {
26 | return io.Compound.String()
27 | }
28 |
29 | if len(io.Name) > 0 {
30 | return io.Name + ":" + io.Type.String()
31 | }
32 | return io.Type.String()
33 | }
34 |
35 | // Parse parses the I/O argument from the input string values.
36 | func (io IOArg) Parse(inputs []string) (*big.Int, error) {
37 | result := new(big.Int)
38 |
39 | if len(io.Compound) == 0 {
40 | if len(inputs) != 1 {
41 | return nil,
42 | fmt.Errorf("invalid amount of arguments, got %d, expected 1",
43 | len(inputs))
44 | }
45 |
46 | switch io.Type.Type {
47 | case types.TInt, types.TUint:
48 | _, ok := result.SetString(inputs[0], 0)
49 | if !ok {
50 | return nil, fmt.Errorf("invalid input: %s", inputs[0])
51 | }
52 |
53 | case types.TBool:
54 | switch inputs[0] {
55 | case "0", "f", "false":
56 | case "1", "t", "true":
57 | result.SetInt64(1)
58 | default:
59 | return nil, fmt.Errorf("invalid bool constant: %s", inputs[0])
60 | }
61 |
62 | case types.TArray:
63 | count := int(io.Type.ArraySize)
64 | elSize := int(io.Type.ElementType.Bits)
65 |
66 | val := new(big.Int)
67 | _, ok := val.SetString(inputs[0], 0)
68 | if !ok {
69 | return nil, fmt.Errorf("invalid input: %s", inputs[0])
70 | }
71 | var bitLen int
72 | if strings.HasPrefix(inputs[0], "0x") {
73 | bitLen = (len(inputs[0]) - 2) * 4
74 | } else {
75 | bitLen = val.BitLen()
76 | }
77 |
78 | valElCount := bitLen / elSize
79 | if bitLen%elSize != 0 {
80 | valElCount++
81 | }
82 | if valElCount > count {
83 | return nil, fmt.Errorf("too many values for input: %s",
84 | inputs[0])
85 | }
86 | pad := count - valElCount
87 | val.Lsh(val, uint(pad*elSize))
88 |
89 | mask := new(big.Int)
90 | for i := 0; i < elSize; i++ {
91 | mask.SetBit(mask, i, 1)
92 | }
93 |
94 | for i := 0; i < count; i++ {
95 | next := new(big.Int).Rsh(val, uint((count-i-1)*elSize))
96 | next = next.And(next, mask)
97 |
98 | next.Lsh(next, uint(i*elSize))
99 | result.Or(result, next)
100 | }
101 |
102 | default:
103 | return nil, fmt.Errorf("unsupported input type: %s", io.Type)
104 | }
105 |
106 | return result, nil
107 | }
108 | if len(inputs) != len(io.Compound) {
109 | return nil,
110 | fmt.Errorf("invalid amount of arguments, got %d, expected %d",
111 | len(inputs), len(io.Compound))
112 | }
113 |
114 | var offset int
115 |
116 | for idx, arg := range io.Compound {
117 | input, err := arg.Parse(inputs[idx : idx+1])
118 | if err != nil {
119 | return nil, err
120 | }
121 |
122 | input.Lsh(input, uint(offset))
123 | result.Or(result, input)
124 |
125 | offset += int(arg.Type.Bits)
126 | }
127 | return result, nil
128 | }
129 |
130 | // InputSizes computes the bit sizes of the input arguments. This is
131 | // used for parametrized main() when the program is instantiated based
132 | // on input sizes.
133 | func InputSizes(inputs []string) ([]int, error) {
134 | var result []int
135 |
136 | for _, input := range inputs {
137 | switch input {
138 | case "0", "f", "false", "1", "t", "true":
139 | result = append(result, 1)
140 |
141 | default:
142 | if strings.HasPrefix(input, "0x") {
143 | result = append(result, (len(input)-2)*4)
144 | } else {
145 | val := new(big.Int)
146 | _, ok := val.SetString(input, 0)
147 | if !ok {
148 | return nil, fmt.Errorf("invalid input: %s", input)
149 | }
150 | result = append(result, val.BitLen())
151 | }
152 | }
153 | }
154 |
155 | return result, nil
156 | }
157 |
--------------------------------------------------------------------------------
/circuit/ioarg_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | var inputSizeTests = []struct {
14 | inputs []string
15 | sizes []int
16 | }{
17 | {
18 | inputs: []string{
19 | "0", "f", "false", "1", "t", "true",
20 | },
21 | sizes: []int{
22 | 1, 1, 1, 1, 1, 1,
23 | },
24 | },
25 | {
26 | inputs: []string{
27 | "0xdeadbeef", "255",
28 | },
29 | sizes: []int{
30 | 32, 8,
31 | },
32 | },
33 | {
34 | inputs: []string{
35 | "0x0", "0x00", "0x000", "0x0000",
36 | },
37 | sizes: []int{
38 | 4, 8, 12, 16,
39 | },
40 | },
41 | }
42 |
43 | func TestInputSizes(t *testing.T) {
44 | for idx, test := range inputSizeTests {
45 | sizes, err := InputSizes(test.inputs)
46 | if err != nil {
47 | t.Errorf("t%v: InputSizes(%v) failed: %v", idx, test.inputs, err)
48 | continue
49 | }
50 | if len(sizes) != len(test.sizes) {
51 | t.Errorf("t%v: unexpected # of sizes: got %v, expected %v",
52 | idx, len(sizes), len(test.sizes))
53 | continue
54 | }
55 | for i := 0; i < len(sizes); i++ {
56 | if sizes[i] != test.sizes[i] {
57 | t.Errorf("t%v: sizes[%v]=%v, expected %v",
58 | idx, i, sizes[i], test.sizes[i])
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/circuit/marshal.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2021, 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "encoding/binary"
11 | "fmt"
12 | "io"
13 | )
14 |
15 | const (
16 | // MAGIC is a magic number for the QCL circuit format version 0.
17 | MAGIC = 0x63726300 // crc0
18 | )
19 |
20 | var (
21 | bo = binary.BigEndian
22 | )
23 |
24 | // MarshalFormat marshals circuit in the specified format.
25 | func (c *Circuit) MarshalFormat(out io.Writer, format string) error {
26 | switch format {
27 | case "qclc":
28 | return c.Marshal(out)
29 | case "bristol":
30 | return c.MarshalBristol(out)
31 | default:
32 | return fmt.Errorf("unsupported circuit format: %s", format)
33 | }
34 | }
35 |
36 | // Marshal marshals circuit in the QCL circuit format.
37 | func (c *Circuit) Marshal(out io.Writer) error {
38 | var data = []interface{}{
39 | uint32(MAGIC),
40 | uint32(c.NumGates),
41 | uint32(c.NumWires),
42 | uint32(len(c.Inputs)),
43 | uint32(len(c.Outputs)),
44 | }
45 | for _, v := range data {
46 | if err := binary.Write(out, bo, v); err != nil {
47 | return err
48 | }
49 | }
50 | for _, input := range c.Inputs {
51 | if err := marshalIOArg(out, input); err != nil {
52 | return err
53 | }
54 | }
55 | for _, output := range c.Outputs {
56 | if err := marshalIOArg(out, output); err != nil {
57 | return err
58 | }
59 | }
60 |
61 | for _, g := range c.Gates {
62 | switch g.Op {
63 | case XOR, XNOR, AND, OR:
64 | data = []interface{}{
65 | byte(g.Op),
66 | uint32(g.Input0), uint32(g.Input1), uint32(g.Output),
67 | }
68 |
69 | case INV:
70 | data = []interface{}{
71 | byte(g.Op),
72 | uint32(g.Input0), uint32(g.Output),
73 | }
74 | default:
75 | return fmt.Errorf("unsupported gate type %s", g.Op)
76 | }
77 | for _, v := range data {
78 | if err := binary.Write(out, bo, v); err != nil {
79 | return err
80 | }
81 | }
82 | }
83 | return nil
84 | }
85 |
86 | func marshalIOArg(out io.Writer, arg IOArg) error {
87 | if err := marshalString(out, arg.Name); err != nil {
88 | return err
89 | }
90 | if err := marshalString(out, arg.Type.String()); err != nil {
91 | return err
92 | }
93 | if err := binary.Write(out, bo, uint32(arg.Type.Bits)); err != nil {
94 | return err
95 | }
96 | if err := binary.Write(out, bo, uint32(len(arg.Compound))); err != nil {
97 | return err
98 | }
99 | for _, c := range arg.Compound {
100 | if err := marshalIOArg(out, c); err != nil {
101 | return err
102 | }
103 | }
104 | return nil
105 | }
106 |
107 | func marshalString(out io.Writer, val string) error {
108 | bytes := []byte(val)
109 | if err := binary.Write(out, bo, uint32(len(bytes))); err != nil {
110 | return err
111 | }
112 | _, err := out.Write(bytes)
113 | return err
114 | }
115 |
116 | // MarshalBristol marshals the circuit in the Bristol format.
117 | func (c *Circuit) MarshalBristol(out io.Writer) error {
118 | fmt.Fprintf(out, "%d %d\n", c.NumGates, c.NumWires)
119 | fmt.Fprintf(out, "%d", len(c.Inputs))
120 | for _, input := range c.Inputs {
121 | fmt.Fprintf(out, " %d", input.Type.Bits)
122 | }
123 | fmt.Fprintln(out)
124 | fmt.Fprintf(out, "%d", len(c.Outputs))
125 | for _, ret := range c.Outputs {
126 | fmt.Fprintf(out, " %d", ret.Type.Bits)
127 | }
128 | fmt.Fprintln(out)
129 | fmt.Fprintln(out)
130 |
131 | for _, g := range c.Gates {
132 | fmt.Fprintf(out, "%d 1", len(g.Inputs()))
133 | for _, w := range g.Inputs() {
134 | fmt.Fprintf(out, " %d", w)
135 | }
136 | fmt.Fprintf(out, " %d", g.Output)
137 | fmt.Fprintf(out, " %s\n", g.Op)
138 | }
139 |
140 | return nil
141 | }
142 |
--------------------------------------------------------------------------------
/circuit/parser_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // parser_test.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuit
10 |
11 | import (
12 | "bytes"
13 | "testing"
14 | )
15 |
16 | var data = `1 3
17 | 2 1 1
18 | 1 1
19 |
20 | 2 1 0 1 2 AND
21 | `
22 |
23 | func TestParse(t *testing.T) {
24 | _, err := ParseBristol(bytes.NewReader([]byte(data)))
25 | if err != nil {
26 | t.Fatalf("Parse failed: %s", err)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/circuit/template.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2022 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "fmt"
11 | "regexp"
12 | "strconv"
13 | "strings"
14 | )
15 |
16 | var reVar = regexp.MustCompilePOSIX(`{(.?){([^\}]+)}}`)
17 |
18 | // Template defines an expandable text template.
19 | type Template struct {
20 | parts []*part
21 | FloatCvt FloatCvt
22 | IntCvt IntCvt
23 | StringCvt StringCvt
24 | }
25 |
26 | // FloatCvt converts a float64 value to float64 value.
27 | type FloatCvt func(v float64) float64
28 |
29 | // IntCvt converts an integer value to float64 value.
30 | type IntCvt func(v int) float64
31 |
32 | // StringCvt converts a string value to a string value.
33 | type StringCvt func(v string) string
34 |
35 | const (
36 | partFloat = iota
37 | partInt
38 | partString
39 | )
40 |
41 | type part struct {
42 | t int
43 | fv float64
44 | iv int
45 | sv string
46 | }
47 |
48 | func (p part) String() string {
49 | switch p.t {
50 | case partFloat:
51 | return fmt.Sprintf("float64:%v", p.fv)
52 | case partInt:
53 | return fmt.Sprintf("int:%v", p.iv)
54 | case partString:
55 | return p.sv
56 | default:
57 | return fmt.Sprintf("{part %d}", p.t)
58 | }
59 | }
60 |
61 | // NewTemplate parses the input string and returns the parsed
62 | // Template.
63 | func NewTemplate(input string) *Template {
64 | t := &Template{
65 | FloatCvt: func(v float64) float64 { return v },
66 | IntCvt: func(v int) float64 { return float64(v) },
67 | StringCvt: func(v string) string { return v },
68 | }
69 | matches := reVar.FindAllStringSubmatchIndex(input, -1)
70 | if matches == nil {
71 | return t
72 | }
73 |
74 | var start int
75 | var err error
76 |
77 | for _, m := range matches {
78 | if m[0] > start {
79 | t.parts = append(t.parts, &part{
80 | t: partString,
81 | sv: input[start:m[0]],
82 | })
83 | }
84 | content := input[m[4]:m[5]]
85 | part := &part{
86 | t: partFloat,
87 | sv: content,
88 | }
89 | t.parts = append(t.parts, part)
90 | start = m[1]
91 |
92 | if m[2] != m[3] {
93 | switch input[m[2]:m[3]] {
94 | default:
95 | panic(fmt.Sprintf("unknown template variable conversion: %s",
96 | input[m[2]:m[3]]))
97 | }
98 | } else {
99 | part.iv, err = strconv.Atoi(content)
100 | if err == nil {
101 | part.t = partInt
102 | } else {
103 | part.fv, err = strconv.ParseFloat(content, 64)
104 | if err == nil {
105 | part.t = partFloat
106 | } else {
107 | part.sv = content
108 | part.t = partString
109 | }
110 | }
111 | }
112 |
113 | }
114 | if start < len(input) {
115 | t.parts = append(t.parts, &part{
116 | t: partString,
117 | sv: input[start:],
118 | })
119 | }
120 |
121 | return t
122 | }
123 |
124 | // Expand expands the template.
125 | func (t *Template) Expand() string {
126 | var b strings.Builder
127 |
128 | for _, part := range t.parts {
129 | switch part.t {
130 | case partFloat:
131 | b.WriteString(fmt.Sprintf("%v", t.FloatCvt(part.fv)))
132 | case partInt:
133 | b.WriteString(fmt.Sprintf("%v", t.IntCvt(part.iv)))
134 | case partString:
135 | b.WriteString(part.sv)
136 | default:
137 | panic(fmt.Sprintf("invalid part type: %v", part.t))
138 | }
139 | }
140 |
141 | return b.String()
142 | }
143 |
--------------------------------------------------------------------------------
/circuit/template_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2022-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | var tmplXOR = `
44 | `
45 |
46 | var tmplXORExpanded = `
77 | `
78 |
79 | func TestTemplate(t *testing.T) {
80 | tmpl := NewTemplate(tmplXOR)
81 | tmpl.IntCvt = func(v int) float64 {
82 | return float64(v) * 25 / 100
83 | }
84 | expanded := tmpl.Expand()
85 | if expanded != tmplXORExpanded {
86 | t.Errorf("template expansion failed: got\n%v\n", expanded)
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/circuit/timing.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuit
8 |
9 | import (
10 | "time"
11 | )
12 |
13 | // Timing records timing samples and renders a profiling report.
14 | type Timing struct {
15 | Start time.Time
16 | Samples []*Sample
17 | }
18 |
19 | // NewTiming creates a new Timing instance.
20 | func NewTiming() *Timing {
21 | return &Timing{
22 | Start: time.Now(),
23 | }
24 | }
25 |
26 | // Sample adds a timing sample with label and data columns.
27 | func (t *Timing) Sample(label string, cols []string) *Sample {
28 | start := t.Start
29 | if len(t.Samples) > 0 {
30 | start = t.Samples[len(t.Samples)-1].End
31 | }
32 | sample := &Sample{
33 | Label: label,
34 | Start: start,
35 | End: time.Now(),
36 | Cols: cols,
37 | }
38 | t.Samples = append(t.Samples, sample)
39 | return sample
40 | }
41 |
42 | // Sample contains information about one timing sample.
43 | type Sample struct {
44 | Label string
45 | Start time.Time
46 | End time.Time
47 | Abs time.Duration
48 | Cols []string
49 | Samples []*Sample
50 | }
51 |
52 | // SubSample adds a sub-sample for a timing sample.
53 | func (s *Sample) SubSample(label string, end time.Time) {
54 | start := s.Start
55 | if len(s.Samples) > 0 {
56 | start = s.Samples[len(s.Samples)-1].End
57 | }
58 | s.Samples = append(s.Samples, &Sample{
59 | Label: label,
60 | Start: start,
61 | End: end,
62 | })
63 | }
64 |
65 | // AbsSubSample adds an absolute sub-sample for a timing sample.
66 | func (s *Sample) AbsSubSample(label string, duration time.Duration) {
67 | s.Samples = append(s.Samples, &Sample{
68 | Label: label,
69 | Abs: duration,
70 | })
71 | }
72 |
--------------------------------------------------------------------------------
/compiler/.gitignore:
--------------------------------------------------------------------------------
1 | *.circ
2 |
--------------------------------------------------------------------------------
/compiler/circuits/allocator.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "fmt"
11 | "unsafe"
12 |
13 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
14 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
15 | )
16 |
17 | var (
18 | sizeofWire = uint64(unsafe.Sizeof(Wire{}))
19 | sizeofGate = uint64(unsafe.Sizeof(Gate{}))
20 | )
21 |
22 | // Allocator implements circuit wire and gate allocation.
23 | type Allocator struct {
24 | numWire uint64
25 | numWires uint64
26 | numGates uint64
27 | }
28 |
29 | // NewAllocator creates a new circuit allocator.
30 | func NewAllocator() *Allocator {
31 | return new(Allocator)
32 | }
33 |
34 | // Wire allocates a new Wire.
35 | func (alloc *Allocator) Wire() *Wire {
36 | alloc.numWire++
37 | w := new(Wire)
38 | w.Reset(UnassignedID)
39 | return w
40 | }
41 |
42 | // Wires allocate an array of Wires.
43 | func (alloc *Allocator) Wires(bits types.Size) []*Wire {
44 | alloc.numWires += uint64(bits)
45 |
46 | wires := make([]Wire, bits)
47 | result := make([]*Wire, bits)
48 | for i := 0; i < int(bits); i++ {
49 | w := &wires[i]
50 | w.id = UnassignedID
51 | result[i] = w
52 | }
53 | return result
54 | }
55 |
56 | // BinaryGate creates a new binary gate.
57 | func (alloc *Allocator) BinaryGate(op circuit.Operation, a, b, o *Wire) *Gate {
58 | alloc.numGates++
59 | gate := &Gate{
60 | Op: op,
61 | A: a,
62 | B: b,
63 | O: o,
64 | }
65 | a.AddOutput(gate)
66 | b.AddOutput(gate)
67 | o.SetInput(gate)
68 |
69 | return gate
70 | }
71 |
72 | // INVGate creates a new INV gate.
73 | func (alloc *Allocator) INVGate(i, o *Wire) *Gate {
74 | alloc.numGates++
75 | gate := &Gate{
76 | Op: circuit.INV,
77 | A: i,
78 | O: o,
79 | }
80 | i.AddOutput(gate)
81 | o.SetInput(gate)
82 |
83 | return gate
84 | }
85 |
86 | // Debug print debugging information about the circuit allocator.
87 | func (alloc *Allocator) Debug() {
88 | wireSize := circuit.FileSize(alloc.numWire * sizeofWire)
89 | wiresSize := circuit.FileSize(alloc.numWires * sizeofWire)
90 | gatesSize := circuit.FileSize(alloc.numGates * sizeofGate)
91 |
92 | total := float64(wireSize + wiresSize + gatesSize)
93 |
94 | fmt.Println("circuits.Allocator:")
95 | fmt.Printf(" wire : %9v %5s %5.2f%%\n",
96 | alloc.numWire, wireSize, float64(wireSize)/total*100.0)
97 | fmt.Printf(" wires: %9v %5s %5.2f%%\n",
98 | alloc.numWires, wiresSize, float64(wiresSize)/total*100.0)
99 | fmt.Printf(" gates: %9v %5s %5.2f%%\n",
100 | alloc.numGates, gatesSize, float64(gatesSize)/total*100.0)
101 | }
102 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_adder.go:
--------------------------------------------------------------------------------
1 | //
2 | // circ_adder.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuits
10 |
11 | import (
12 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
13 | )
14 |
15 | // NewHalfAdder creates a half adder circuit.
16 | func NewHalfAdder(cc *Compiler, a, b, s, c *Wire) {
17 | // S = XOR(A, B)
18 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, a, b, s))
19 |
20 | if c != nil {
21 | // C = AND(A, B)
22 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, a, b, c))
23 | }
24 | }
25 |
26 | // NewFullAdder creates a full adder circuit
27 | func NewFullAdder(cc *Compiler, a, b, cin, s, cout *Wire) {
28 | w1 := cc.Calloc.Wire()
29 | w2 := cc.Calloc.Wire()
30 | w3 := cc.Calloc.Wire()
31 |
32 | // s = a XOR b XOR cin
33 | // cout = cin XOR ((a XOR cin) AND (b XOR cin)).
34 |
35 | // w1 = XOR(b, cin)
36 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, b, cin, w1))
37 |
38 | // s = XOR(a, w1)
39 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, a, w1, s))
40 |
41 | if cout != nil {
42 | // w2 = XOR(a, cin)
43 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, a, cin, w2))
44 |
45 | // w3 = AND(w1, w2)
46 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, w1, w2, w3))
47 |
48 | // cout = XOR(cin, w3)
49 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, cin, w3, cout))
50 | }
51 | }
52 |
53 | // NewAdder creates a new adder circuit implementing z=x+y.
54 | func NewAdder(cc *Compiler, x, y, z []*Wire) error {
55 | x, y = cc.ZeroPad(x, y)
56 | if len(x) > len(z) {
57 | x = x[0:len(z)]
58 | y = y[0:len(z)]
59 | }
60 |
61 | if len(x) == 1 {
62 | var cin *Wire
63 | if len(z) > 1 {
64 | cin = z[1]
65 | }
66 | NewHalfAdder(cc, x[0], y[0], z[0], cin)
67 | } else {
68 | cin := cc.Calloc.Wire()
69 | NewHalfAdder(cc, x[0], y[0], z[0], cin)
70 |
71 | for i := 1; i < len(x); i++ {
72 | var cout *Wire
73 | if i+1 >= len(x) {
74 | if i+1 >= len(z) {
75 | // N+N=N, overflow, drop carry bit.
76 | cout = nil
77 | } else {
78 | cout = z[len(x)]
79 | }
80 | } else {
81 | cout = cc.Calloc.Wire()
82 | }
83 |
84 | NewFullAdder(cc, x[i], y[i], cin, z[i], cout)
85 |
86 | cin = cout
87 | }
88 | }
89 |
90 | // Set all leftover bits to zero.
91 | for i := len(x) + 1; i < len(z); i++ {
92 | z[i] = cc.ZeroWire()
93 | }
94 |
95 | return nil
96 | }
97 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_binary.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2021, 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
11 | )
12 |
13 | // NewBinaryAND creates a new binary AND circuit implementing r=x&y
14 | func NewBinaryAND(cc *Compiler, x, y, r []*Wire) error {
15 | x, y = cc.ZeroPad(x, y)
16 | if len(r) < len(x) {
17 | x = x[0:len(r)]
18 | y = y[0:len(r)]
19 | }
20 | for i := 0; i < len(x); i++ {
21 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, x[i], y[i], r[i]))
22 | }
23 | return nil
24 | }
25 |
26 | // NewBinaryClear creates a new binary clear circuit implementing r=x&^y.
27 | func NewBinaryClear(cc *Compiler, x, y, r []*Wire) error {
28 | x, y = cc.ZeroPad(x, y)
29 | if len(r) < len(x) {
30 | x = x[0:len(r)]
31 | y = y[0:len(r)]
32 | }
33 | for i := 0; i < len(x); i++ {
34 | w := cc.Calloc.Wire()
35 | cc.INV(y[i], w)
36 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, x[i], w, r[i]))
37 | }
38 | return nil
39 | }
40 |
41 | // NewBinaryOR creates a new binary OR circuit implementing r=x|y.
42 | func NewBinaryOR(cc *Compiler, x, y, r []*Wire) error {
43 | x, y = cc.ZeroPad(x, y)
44 | if len(r) < len(x) {
45 | x = x[0:len(r)]
46 | y = y[0:len(r)]
47 | }
48 | for i := 0; i < len(x); i++ {
49 | cc.AddGate(cc.Calloc.BinaryGate(circuit.OR, x[i], y[i], r[i]))
50 | }
51 | return nil
52 | }
53 |
54 | // NewBinaryXOR creates a new binary XOR circuit implementing r=x^y.
55 | func NewBinaryXOR(cc *Compiler, x, y, r []*Wire) error {
56 | x, y = cc.ZeroPad(x, y)
57 | if len(r) < len(x) {
58 | x = x[0:len(r)]
59 | y = y[0:len(r)]
60 | }
61 | for i := 0; i < len(x); i++ {
62 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, x[i], y[i], r[i]))
63 | }
64 | return nil
65 | }
66 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_divider.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | // NewDivider creates a division circuit computing r=a/b, q=a%b.
10 | func NewDivider(cc *Compiler, a, b, q, r []*Wire) error {
11 | a, b = cc.ZeroPad(a, b)
12 |
13 | rIn := make([]*Wire, len(b)+1)
14 | rOut := make([]*Wire, len(b)+1)
15 |
16 | // Init bINV.
17 | bINV := make([]*Wire, len(b))
18 | for i := 0; i < len(b); i++ {
19 | bINV[i] = cc.Calloc.Wire()
20 | cc.INV(b[i], bINV[i])
21 | }
22 |
23 | // Init for the first row.
24 | for i := 0; i < len(b); i++ {
25 | rOut[i] = cc.ZeroWire()
26 | }
27 |
28 | // Generate matrix.
29 | for y := 0; y < len(a); y++ {
30 | // Init rIn.
31 | rIn[0] = a[len(a)-1-y]
32 | copy(rIn[1:], rOut)
33 |
34 | // Adders from b{0} to b{n-1}, 0
35 | cIn := cc.OneWire()
36 | for x := 0; x < len(b)+1; x++ {
37 | var bw *Wire
38 | if x < len(b) {
39 | bw = bINV[x]
40 | } else {
41 | bw = cc.OneWire() // INV(0)
42 | }
43 | co := cc.Calloc.Wire()
44 | ro := cc.Calloc.Wire()
45 | NewFullAdder(cc, rIn[x], bw, cIn, ro, co)
46 | rOut[x] = ro
47 | cIn = co
48 | }
49 |
50 | // Quotient y.
51 | if len(a)-1-y < len(q) {
52 | w := cc.Calloc.Wire()
53 | cc.INV(cIn, w)
54 | cc.INV(w, q[len(a)-1-y])
55 | }
56 |
57 | // MUXes from high to low bit.
58 | for x := len(b); x >= 0; x-- {
59 | var ro *Wire
60 | if y+1 >= len(a) && x < len(r) {
61 | ro = r[x]
62 | } else {
63 | ro = cc.Calloc.Wire()
64 | }
65 |
66 | err := NewMUX(cc, []*Wire{cIn}, rOut[x:x+1], rIn[x:x+1],
67 | []*Wire{ro})
68 | if err != nil {
69 | return err
70 | }
71 | rOut[x] = ro
72 | }
73 | }
74 |
75 | // Set extra quotient bits to zero.
76 | for y := len(a); y < len(q); y++ {
77 | q[y] = cc.ZeroWire()
78 | }
79 |
80 | // Set extra remainder bits to zero.
81 | for x := len(b); x < len(r); x++ {
82 | r[x] = cc.ZeroWire()
83 | }
84 |
85 | return nil
86 | }
87 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_hamming.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
11 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
12 | )
13 |
14 | // Hamming creates a hamming distance circuit computing the hamming
15 | // distance between a and b and returning the distance in r.
16 | func Hamming(cc *Compiler, a, b, r []*Wire) error {
17 | a, b = cc.ZeroPad(a, b)
18 |
19 | var arr [][]*Wire
20 | for i := 0; i < len(a); i++ {
21 | w := cc.Calloc.Wire()
22 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, a[i], b[i], w))
23 | arr = append(arr, []*Wire{w})
24 | }
25 |
26 | for len(arr) > 2 {
27 | var n [][]*Wire
28 | for i := 0; i < len(arr); i += 2 {
29 | if i+1 < len(arr) {
30 | result := cc.Calloc.Wires(types.Size(len(arr[i]) + 1))
31 | err := NewAdder(cc, arr[i], arr[i+1], result)
32 | if err != nil {
33 | return err
34 | }
35 | n = append(n, result)
36 | } else {
37 | n = append(n, arr[i])
38 | }
39 | }
40 | arr = n
41 | }
42 |
43 | return NewAdder(cc, arr[0], arr[1], r)
44 | }
45 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_index.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2021-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "fmt"
11 | )
12 |
13 | // NewIndex creates a new array element selection (index) circuit.
14 | func NewIndex(cc *Compiler, size int, array, index, out []*Wire) error {
15 | if len(array)%size != 0 {
16 | return fmt.Errorf("array width %d must be multiple of element size %d",
17 | len(array), size)
18 | }
19 | if len(out) < size {
20 | return fmt.Errorf("out %d too small for element size %d",
21 | len(out), size)
22 | }
23 | n := len(array) / size
24 | if n == 0 {
25 | for i := 0; i < len(out); i++ {
26 | out[i] = cc.ZeroWire()
27 | }
28 | return nil
29 | }
30 |
31 | bits := 1
32 | var length int
33 |
34 | for length = 2; length < n; length *= 2 {
35 | bits++
36 | }
37 |
38 | return newIndex(cc, bits-1, length, size, array, index, out)
39 | }
40 |
41 | func newIndex(cc *Compiler, bit, length, size int,
42 | array, index, out []*Wire) error {
43 |
44 | // Default "not found" value.
45 | def := make([]*Wire, size)
46 | for i := 0; i < size; i++ {
47 | def[i] = cc.ZeroWire()
48 | }
49 |
50 | n := len(array) / size
51 |
52 | if bit == 0 {
53 | fVal := array[:size]
54 |
55 | var tVal []*Wire
56 | if n > 1 {
57 | tVal = array[size : 2*size]
58 | } else {
59 | tVal = def
60 | }
61 | return NewMUX(cc, index[0:1], tVal, fVal, out)
62 | }
63 |
64 | length /= 2
65 | fArray := array
66 | if n > length {
67 | fArray = fArray[:length*size]
68 | }
69 |
70 | if bit >= len(index) {
71 | // Not enough bits to select upper half so just select from
72 | // the lower half.
73 | return newIndex(cc, bit-1, length, size, fArray, index, out)
74 | }
75 |
76 | fVal := make([]*Wire, size)
77 | for i := 0; i < size; i++ {
78 | fVal[i] = cc.Calloc.Wire()
79 | }
80 | err := newIndex(cc, bit-1, length, size, fArray, index, fVal)
81 | if err != nil {
82 | return err
83 | }
84 |
85 | var tVal []*Wire
86 | if n > length {
87 | tVal = make([]*Wire, size)
88 | for i := 0; i < size; i++ {
89 | tVal[i] = cc.Calloc.Wire()
90 | }
91 | err = newIndex(cc, bit-1, length, size,
92 | array[length*size:], index, tVal)
93 | if err != nil {
94 | return err
95 | }
96 | } else {
97 | tVal = def
98 | }
99 |
100 | return NewMUX(cc, index[bit:bit+1], tVal, fVal, out)
101 | }
102 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_mux.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "fmt"
11 |
12 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
13 | )
14 |
15 | // NewMUX creates a multiplexer circuit that selects the input t or f
16 | // to output, based on the value of the condition cond.
17 | func NewMUX(cc *Compiler, cond, t, f, out []*Wire) error {
18 | t, f = cc.ZeroPad(t, f)
19 | if len(cond) != 1 || len(t) != len(f) || len(t) != len(out) {
20 | return fmt.Errorf("invalid mux arguments: cond=%d, l=%d, r=%d, out=%d",
21 | len(cond), len(t), len(f), len(out))
22 | }
23 |
24 | for i := 0; i < len(t); i++ {
25 | w1 := cc.Calloc.Wire()
26 | w2 := cc.Calloc.Wire()
27 |
28 | // w1 = XOR(f[i], t[i])
29 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, f[i], t[i], w1))
30 |
31 | // w2 = AND(w1, cond)
32 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, w1, cond[0], w2))
33 |
34 | // out[i] = XOR(w2, f[i])
35 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, w2, f[i], out[i]))
36 | }
37 |
38 | return nil
39 | }
40 |
--------------------------------------------------------------------------------
/compiler/circuits/circ_subtractor.go:
--------------------------------------------------------------------------------
1 | //
2 | // circ_subtractor.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuits
10 |
11 | import (
12 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
13 | )
14 |
15 | // NewFullSubtractor creates a full subtractor circuit.
16 | func NewFullSubtractor(cc *Compiler, x, y, cin, d, cout *Wire) {
17 | w1 := cc.Calloc.Wire()
18 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XNOR, y, cin, w1))
19 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XNOR, x, w1, d))
20 |
21 | if cout != nil {
22 | w2 := cc.Calloc.Wire()
23 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, x, cin, w2))
24 |
25 | w3 := cc.Calloc.Wire()
26 | cc.AddGate(cc.Calloc.BinaryGate(circuit.AND, w1, w2, w3))
27 |
28 | cc.AddGate(cc.Calloc.BinaryGate(circuit.XOR, w3, cin, cout))
29 | }
30 | }
31 |
32 | // NewSubtractor creates a new subtractor circuit implementing z=x-y.
33 | func NewSubtractor(cc *Compiler, x, y, z []*Wire) error {
34 | x, y = cc.ZeroPad(x, y)
35 | if len(x) > len(z) {
36 | x = x[0:len(z)]
37 | y = y[0:len(z)]
38 | }
39 | cin := cc.ZeroWire()
40 |
41 | for i := 0; i < len(x); i++ {
42 | var cout *Wire
43 | if i+1 >= len(x) {
44 | if i+1 >= len(z) {
45 | // N-N=N, overflow, drop carry bit.
46 | cout = nil
47 | } else {
48 | cout = z[i+1]
49 | }
50 | } else {
51 | cout = cc.Calloc.Wire()
52 | }
53 |
54 | // Note y-x here.
55 | NewFullSubtractor(cc, y[i], x[i], cin, z[i], cout)
56 |
57 | cin = cout
58 | }
59 | for i := len(x) + 1; i < len(z); i++ {
60 | z[i] = cc.ZeroWire()
61 | }
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/compiler/circuits/circuits_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // circuits_test.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuits
10 |
11 | import (
12 | "fmt"
13 | "os"
14 | "testing"
15 |
16 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
17 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
18 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
19 | )
20 |
21 | const (
22 | verbose = false
23 | )
24 |
25 | var (
26 | params = utils.NewParams()
27 | calloc = NewAllocator()
28 | )
29 |
30 | func makeWires(count int, output bool) []*Wire {
31 | var result []*Wire
32 | for i := 0; i < count; i++ {
33 | w := calloc.Wire()
34 | w.SetOutput(output)
35 | result = append(result, w)
36 | }
37 | return result
38 | }
39 |
40 | func NewIO(size int, name string) circuit.IO {
41 | return circuit.IO{
42 | circuit.IOArg{
43 | Name: name,
44 | Type: types.Info{
45 | Type: types.TUint,
46 | IsConcrete: true,
47 | Bits: types.Size(size),
48 | },
49 | },
50 | }
51 | }
52 |
53 | func TestAdd4(t *testing.T) {
54 | bits := 4
55 |
56 | // 2xbits inputs, bits+1 outputs
57 | inputs := makeWires(bits*2, false)
58 | outputs := makeWires(bits+1, true)
59 | c, err := NewCompiler(params, calloc, NewIO(bits*2, "in"),
60 | NewIO(bits+1, "out"), inputs, outputs)
61 | if err != nil {
62 | t.Fatalf("NewCompiler: %s", err)
63 | }
64 |
65 | cin := calloc.Wire()
66 | NewHalfAdder(c, inputs[0], inputs[bits], outputs[0], cin)
67 |
68 | for i := 1; i < bits; i++ {
69 | var cout *Wire
70 | if i+1 >= bits {
71 | cout = outputs[bits]
72 | } else {
73 | cout = calloc.Wire()
74 | }
75 |
76 | NewFullAdder(c, inputs[i], inputs[bits+i], cin, outputs[i], cout)
77 |
78 | cin = cout
79 | }
80 |
81 | result := c.Compile()
82 | if verbose {
83 | fmt.Printf("Result: %s\n", result)
84 | result.Marshal(os.Stdout)
85 | }
86 | }
87 |
88 | func TestFullSubtractor(t *testing.T) {
89 | inputs := makeWires(1+2, false)
90 | outputs := makeWires(2, true)
91 | c, err := NewCompiler(params, calloc, NewIO(1+2, "in"), NewIO(2, "out"),
92 | inputs, outputs)
93 | if err != nil {
94 | t.Fatalf("NewCompiler: %s", err)
95 | }
96 |
97 | NewFullSubtractor(c, inputs[0], inputs[1], inputs[2],
98 | outputs[0], outputs[1])
99 |
100 | result := c.Compile()
101 | if verbose {
102 | fmt.Printf("Result: %s\n", result)
103 | result.Marshal(os.Stdout)
104 | }
105 | }
106 |
107 | func TestMultiply1(t *testing.T) {
108 | inputs := makeWires(2, false)
109 | outputs := makeWires(2, true)
110 | c, err := NewCompiler(params, calloc, NewIO(2, "in"), NewIO(2, "out"),
111 | inputs, outputs)
112 | if err != nil {
113 | t.Fatalf("NewCompiler: %s", err)
114 | }
115 |
116 | err = NewMultiplier(c, 0, inputs[0:1], inputs[1:2], outputs)
117 | if err != nil {
118 | t.Error(err)
119 | }
120 | }
121 |
122 | func TestMultiply(t *testing.T) {
123 | bits := 64
124 |
125 | inputs := makeWires(bits*2, false)
126 | outputs := makeWires(bits*2, true)
127 |
128 | c, err := NewCompiler(params, calloc, NewIO(bits*2, "in"),
129 | NewIO(bits*2, "out"), inputs, outputs)
130 | if err != nil {
131 | t.Fatalf("NewCompiler: %s", err)
132 | }
133 |
134 | err = NewMultiplier(c, 0, inputs[0:bits], inputs[bits:2*bits], outputs)
135 | if err != nil {
136 | t.Error(err)
137 | }
138 |
139 | result := c.Compile()
140 | if verbose {
141 | fmt.Printf("Result: %s\n", result)
142 | result.Marshal(os.Stdout)
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/compiler/circuits/gates.go:
--------------------------------------------------------------------------------
1 | //
2 | // gates.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package circuits
10 |
11 | import (
12 | "fmt"
13 |
14 | "source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
15 | )
16 |
17 | // Gate implements binary gates.
18 | type Gate struct {
19 | Op circuit.Operation
20 | Visited bool
21 | Compiled bool
22 | Dead bool
23 | A *Wire
24 | B *Wire
25 | O *Wire
26 | }
27 |
28 | func (g *Gate) String() string {
29 | return fmt.Sprintf("%s %x %x %x", g.Op, g.A.ID(), g.B.ID(), g.O.ID())
30 | }
31 |
32 | // Visit adds gate to the list of pending gates to be compiled.
33 | func (g *Gate) Visit(cc *Compiler) {
34 | switch g.Op {
35 | case circuit.INV:
36 | if !g.Dead && !g.Visited && g.A.Assigned() {
37 | g.Visited = true
38 | cc.pending = append(cc.pending, g)
39 | }
40 |
41 | default:
42 | if !g.Dead && !g.Visited && g.A.Assigned() && g.B.Assigned() {
43 | g.Visited = true
44 | cc.pending = append(cc.pending, g)
45 | }
46 | }
47 | }
48 |
49 | // ShortCircuit replaces gate with the value of the wire o.
50 | func (g *Gate) ShortCircuit(o *Wire) {
51 | // Do not short circuit output wires.
52 | if g.O.Output() {
53 | return
54 | }
55 |
56 | // Add gate's outputs to short circuit output wire.
57 | g.O.ForEachOutput(func(gate *Gate) {
58 | gate.ReplaceInput(g.O, o)
59 | })
60 | g.O.DisconnectOutputs()
61 | }
62 |
63 | // ResetOutput resets the gate's output with the wire o.
64 | func (g *Gate) ResetOutput(o *Wire) {
65 | g.O = o
66 | }
67 |
68 | // ReplaceInput replaces gate's input wire from with wire to. The
69 | // function panics if from is not gate's input wire.
70 | func (g *Gate) ReplaceInput(from, to *Wire) {
71 | if g.A == from {
72 | g.A.RemoveOutput(g)
73 | to.AddOutput(g)
74 | g.A = to
75 | } else if g.B == from {
76 | g.B.RemoveOutput(g)
77 | to.AddOutput(g)
78 | g.B = to
79 | } else {
80 | panic(fmt.Sprintf("%s is not input for gate %s", from, g))
81 | }
82 | }
83 |
84 | // Prune removes gate from the circuit if gate is dead i.e. its output
85 | // wire is not connected into circuit's output wires.
86 | func (g *Gate) Prune() bool {
87 | if g.Dead || g.O.Output() || g.O.NumOutputs() > 0 {
88 | return false
89 | }
90 | g.Dead = true
91 | switch g.Op {
92 | case circuit.XOR, circuit.XNOR, circuit.AND, circuit.OR:
93 | g.B.RemoveOutput(g)
94 | fallthrough
95 |
96 | case circuit.INV:
97 | g.A.RemoveOutput(g)
98 | }
99 | return true
100 | }
101 |
102 | // Assign assigns gate's output wire ID.
103 | func (g *Gate) Assign(cc *Compiler) {
104 | if !g.Dead {
105 | g.O.Assign(cc)
106 | cc.assigned = append(cc.assigned, g)
107 | }
108 | }
109 |
110 | // Compile adds gate's binary circuit into compile circuit.
111 | func (g *Gate) Compile(cc *Compiler) {
112 | if g.Dead || g.Compiled {
113 | return
114 | }
115 | g.Compiled = true
116 | switch g.Op {
117 | case circuit.INV:
118 | cc.compiled = append(cc.compiled, circuit.Gate{
119 | Input0: circuit.Wire(g.A.ID()),
120 | Output: circuit.Wire(g.O.ID()),
121 | Op: g.Op,
122 | })
123 |
124 | default:
125 | cc.compiled = append(cc.compiled, circuit.Gate{
126 | Input0: circuit.Wire(g.A.ID()),
127 | Input1: circuit.Wire(g.B.ID()),
128 | Output: circuit.Wire(g.O.ID()),
129 | Op: g.Op,
130 | })
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/compiler/circuits/wire_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package circuits
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | func TestWire(t *testing.T) {
14 | w := calloc.Wire()
15 | if w.ID() != UnassignedID {
16 | t.Error("w.ID")
17 | }
18 | w.SetID(42)
19 | if w.ID() != 42 {
20 | t.Error("w.SetID")
21 | }
22 | if !w.Assigned() {
23 | t.Error("Assigned")
24 | }
25 | if w.Output() {
26 | t.Error("Output")
27 | }
28 | w.SetOutput(true)
29 | if !w.Output() {
30 | t.Error("SetOutput")
31 | }
32 | if w.Value() != Unknown {
33 | t.Error("Value")
34 | }
35 | w.SetValue(One)
36 | if w.Value() != One {
37 | t.Error("SetValue")
38 | }
39 | if w.NumOutputs() != 0 {
40 | t.Error("NumOutputs")
41 | }
42 | w.SetNumOutputs(42)
43 | if w.NumOutputs() != 42 {
44 | t.Error("SetNumOutputs")
45 | }
46 | w.SetNumOutputs(1)
47 | if w.NumOutputs() != 1 {
48 | t.Error("SetNumOutputs")
49 | }
50 | if w.Input() != nil {
51 | t.Error("Input")
52 | }
53 | gate := &Gate{}
54 | w.SetInput(gate)
55 | if w.Input() != gate {
56 | t.Error("SetInput")
57 | }
58 |
59 | w.Reset(UnassignedID)
60 | if w.Output() {
61 | t.Error("Reset: Output")
62 | }
63 | if w.Value() != Unknown {
64 | t.Error("Reset: Value")
65 | }
66 | if w.ID() != UnassignedID {
67 | t.Error("Reset: ID")
68 | }
69 | if !w.IsInput() {
70 | t.Error("Reset: IsInput")
71 | }
72 | if w.NumOutputs() != 0 {
73 | t.Error("Reset: NumOutputs")
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/compiler/lexer_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package compiler
8 |
9 | import (
10 | "bytes"
11 | "fmt"
12 | "io"
13 | "testing"
14 | )
15 |
16 | var input = `// This is a very basic add circuit.
17 | // But we start this example with 2 comment lines.
18 |
19 | package main
20 |
21 | func main(a, b int4) int5 {
22 | return a + b + 1
23 | }
24 | `
25 |
26 | func TestLexer(t *testing.T) {
27 | lexer := NewLexer("{data}", bytes.NewReader([]byte(input)))
28 | for {
29 | token, err := lexer.Get()
30 | if err != nil {
31 | if err == io.EOF {
32 | break
33 | }
34 | t.Fatalf("Get failed: %v", err)
35 | }
36 | if false {
37 | fmt.Printf("Token: %s\n", token)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/compiler/parser_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2019 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package compiler
8 |
9 | import (
10 | "bytes"
11 | "fmt"
12 | "os"
13 | "testing"
14 |
15 | "source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
16 | )
17 |
18 | const (
19 | verbose = false
20 | )
21 |
22 | var parserTests = []string{
23 | `
24 | package main
25 | `,
26 | `
27 | package main
28 | func main() {}
29 | `,
30 | `
31 | package main
32 | func main(a int4) {}
33 | `,
34 | `
35 | package main
36 | func main(a int4, b int4) {}
37 | `,
38 | `
39 | package main
40 | func main(a, b int4) {}
41 | `,
42 | `
43 | package main
44 | func main(a, b int4) int5 {}
45 | `,
46 | `
47 | package main
48 | func main(a, b int4) (int5) {}
49 | `,
50 | `
51 | package main
52 | func main(a, b int4) (int5, int6) {}
53 | `,
54 | `
55 | package main
56 | func main(a, b int4) (int5) {
57 | return
58 | }`,
59 | `
60 | package main
61 | func main(a, b int4) (int5) {
62 | return a * b + c * d
63 | }`,
64 | `
65 | package main
66 | func main(a, b int4) (int5) {
67 | return a * b * c
68 | }`,
69 | `
70 | package main
71 | func main(a, b int4) (int5) {
72 | return a + b + c * d + e
73 | }`,
74 | `
75 | package main
76 | func main(a, b int4) (int4) {
77 | if a > b {
78 | return a
79 | }
80 | return b
81 | }`,
82 | `
83 | package main
84 | func main(a, b int4) (int4) {
85 | if a > b {
86 | return a
87 | } else {
88 | return b
89 | }
90 | }`,
91 | `
92 | package main
93 | func main(a, b int4) (int4) {
94 | if a > b || a == b {
95 | return a
96 | } else {
97 | return b
98 | }
99 | }`,
100 | `
101 | package main
102 | func main(a, b int4) int4 {
103 | return max(a, b)
104 | }
105 |
106 | func max(a, b int4) int4 {
107 | if a > b {
108 | return a
109 | }
110 | return v
111 | }
112 | `,
113 | `
114 | package main
115 |
116 | type Foo struct {
117 | A []byte ` + "`json:\"AButDifferent\"`" + `
118 | B []byte ` + "`json:\"BAlsoDifferent\"`" + `
119 | }
120 |
121 | func main(a, b Foo) []byte {
122 | return a.A[0] ^ b.B[0]
123 | }
124 | `,
125 | }
126 |
127 | func TestParser(t *testing.T) {
128 | min := 0
129 | for idx, test := range parserTests {
130 | if idx < min {
131 | continue
132 | }
133 | logger := utils.NewLogger(os.Stdout)
134 | parser := NewParser(fmt.Sprintf("{test %d}", idx), nil, logger,
135 | bytes.NewReader([]byte(test)))
136 | _, err := parser.Parse(nil)
137 | if err != nil {
138 | t.Fatalf("Parse test %d failed: %v", idx, err)
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/compiler/ssa/bindings_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package ssa
8 |
9 | import (
10 | "fmt"
11 | "testing"
12 |
13 | "source.quilibrium.com/quilibrium/monorepo/bedlam/types"
14 | )
15 |
16 | func TestSet(t *testing.T) {
17 | a := new(Bindings)
18 | a.Set(Value{
19 | Name: "a",
20 | }, nil)
21 |
22 | _, ok := a.Get("a")
23 | if !ok {
24 | t.Errorf("binding for value 'a' not found")
25 | }
26 | _, ok = a.Get("b")
27 | if ok {
28 | t.Errorf("non-existing binding for value 'b' found")
29 | }
30 |
31 | a.Set(Value{
32 | Name: "b",
33 | }, nil)
34 | _, ok = a.Get("b")
35 | if !ok {
36 | t.Errorf("binding for value 'b' not found")
37 | }
38 | }
39 |
40 | func TestClone(t *testing.T) {
41 | a := new(Bindings)
42 | a.Set(Value{
43 | Name: "a",
44 | }, nil)
45 | _, ok := a.Get("a")
46 | if !ok {
47 | t.Errorf("binding for value 'a' not found")
48 | }
49 |
50 | b := a.Clone()
51 | _, ok = b.Get("a")
52 | if !ok {
53 | t.Errorf("binding for value 'a' not found")
54 | }
55 | b.Set(Value{
56 | Name: "b",
57 | }, nil)
58 | _, ok = a.Get("b")
59 | if ok {
60 | t.Errorf("non-existing binding for value 'b' found")
61 | }
62 | _, ok = b.Get("b")
63 | if !ok {
64 | t.Errorf("binding for value 'b' not found")
65 | }
66 | }
67 |
68 | func TestMerge(t *testing.T) {
69 | a := new(Bindings)
70 | b := new(Bindings)
71 |
72 | a.Set(Value{
73 | Name: "a",
74 | Type: types.Int32,
75 | }, constInt(1))
76 | a.Set(Value{
77 | Name: "b",
78 | Type: types.Int32,
79 | }, constInt(42))
80 |
81 | b.Set(Value{
82 | Name: "a",
83 | Type: types.Int32,
84 | }, constInt(2))
85 | merged := a.Merge(Value{
86 | Name: "c",
87 | }, b)
88 | if merged.Count() != 2 {
89 | t.Errorf("Bindings.Merge failed: #values: %d != %d", merged.Count(), 2)
90 | }
91 |
92 | bound, ok := merged.Get("b")
93 | if !ok {
94 | t.Errorf("binding for value 'b' not found")
95 | }
96 | _, ok = bound.Bound.(*Value)
97 | if !ok {
98 | t.Errorf("binding for value 'b' is not *Value: %T", bound.Bound)
99 | }
100 | bound, ok = merged.Get("a")
101 | if !ok {
102 | t.Errorf("binding for value 'a' not found")
103 | }
104 | fmt.Printf("merged.a: %v (%T)\n", bound, bound)
105 | _, ok = bound.Bound.(*Select)
106 | if !ok {
107 | t.Errorf("binding for value 'a' is not *Select: %T", bound.Bound)
108 | }
109 | }
110 |
111 | func constInt(i int) *Value {
112 | return &Value{
113 | Name: fmt.Sprintf("%v/i32", i),
114 | Const: true,
115 | Type: types.Int32,
116 | ConstValue: i,
117 | }
118 | }
119 |
120 | func makeBindings(count int) *Bindings {
121 | b := new(Bindings)
122 |
123 | for i := 0; i < count; i++ {
124 | b.Set(Value{
125 | Name: fmt.Sprintf("a%d", i),
126 | Type: types.Int32,
127 | }, constInt(i))
128 | }
129 |
130 | return b
131 | }
132 |
133 | func BenchmarkSet(b *testing.B) {
134 | bindings := makeBindings(20)
135 |
136 | for i := 0; i < b.N; i++ {
137 | bindings.Set(Value{
138 | Name: "b",
139 | Type: types.Int32,
140 | }, constInt(i))
141 | }
142 | }
143 |
144 | func BenchmarkGet(b *testing.B) {
145 | bindings := makeBindings(20)
146 |
147 | for i := 0; i < b.N; i++ {
148 | _, ok := bindings.Get("b")
149 | if ok {
150 | b.Errorf("non-existing item found")
151 | }
152 | }
153 | }
154 |
155 | func BenchmarkClone(b *testing.B) {
156 | bindings := makeBindings(20)
157 |
158 | for i := 0; i < b.N; i++ {
159 | _ = bindings.Clone()
160 | }
161 | }
162 |
163 | func BenchmarkCloneModify(b *testing.B) {
164 | bindings := makeBindings(20)
165 |
166 | for i := 0; i < b.N; i++ {
167 | n := bindings.Clone()
168 | n.Set(Value{
169 | Name: "a",
170 | Type: types.Int32,
171 | }, constInt(i))
172 | }
173 | }
174 |
175 | func BenchmarkMerge(b *testing.B) {
176 | t := makeBindings(20)
177 | f := makeBindings(20)
178 |
179 | for i := 0; i < b.N; i++ {
180 | _ = t.Merge(Value{
181 | Name: "c",
182 | }, f)
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/compiler/ssa/set.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2021 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package ssa
8 |
9 | import (
10 | "sort"
11 | )
12 |
13 | // Set implements value set
14 | type Set map[ValueID]Value
15 |
16 | // NewSet creates a new string value set.
17 | func NewSet() Set {
18 | return make(map[ValueID]Value)
19 | }
20 |
21 | // Add adds a value to the set.
22 | func (set Set) Add(val Value) {
23 | set[val.ID] = val
24 | }
25 |
26 | // Remove removes a value from set set. The operation does nothing if
27 | // the value did not exist in the set.
28 | func (set Set) Remove(val Value) {
29 | delete(set, val.ID)
30 | }
31 |
32 | // Copy creates a copy of the set.
33 | func (set Set) Copy() Set {
34 | result := make(map[ValueID]Value)
35 | for k, v := range set {
36 | result[k] = v
37 | }
38 | return result
39 | }
40 |
41 | // Subtract removes the values of the argument set from the set.
42 | func (set Set) Subtract(o Set) {
43 | for _, v := range o {
44 | set.Remove(v)
45 | }
46 | }
47 |
48 | // Array returns the values of the set as an array.
49 | func (set Set) Array() []Value {
50 | var result []Value
51 | for _, v := range set {
52 | result = append(result, v)
53 | }
54 | sort.Slice(result, func(i, j int) bool {
55 | return result[i].ID < result[j].ID
56 | })
57 | return result
58 | }
59 |
--------------------------------------------------------------------------------
/compiler/ssa/value_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package ssa
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | var inputs = []string{
14 | "$127", "$126", "$125", "$124", "$123", "$122", "$121", "$119",
15 | "$118", "$117", "$116", "$115", "$114", "$113", "$111", "$110",
16 | "$109", "$108", "$107", "$106", "$105", "$103", "$102", "$101",
17 | "$100",
18 | }
19 |
20 | func TestHashCode(t *testing.T) {
21 | counts := make(map[int]int)
22 | for _, input := range inputs {
23 | v := Value{
24 | Name: input,
25 | Const: true,
26 | }
27 | counts[v.HashCode()]++
28 | }
29 |
30 | for k, v := range counts {
31 | if v > 1 {
32 | t.Errorf("HashCode %v: count=%v\n", k, v)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/compiler/tests/array.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Field [10]int32
6 |
7 | // @Test 0 0 = 45
8 | // @Test 0 1 = 46
9 | func main(a, b int32) int {
10 | var arr Field
11 |
12 | for i := 0; i < len(arr); i++ {
13 | arr[i] = i
14 | }
15 |
16 | var sum int32
17 | for i := 0; i < len(arr); i++ {
18 | sum += arr[i]
19 | }
20 |
21 | return sum + b
22 | }
23 |
--------------------------------------------------------------------------------
/compiler/tests/assign2.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 1 7 = 1 7
6 | // @Test 7 1 = 1 7
7 | func main(a, b int32) (int, int) {
8 | min, max := 0, 1
9 | min, max = minMax(a, b)
10 | return min, max
11 | }
12 |
13 | func minMax(a, b int) (int, int) {
14 | if a < b {
15 | return a, b
16 | } else {
17 | return b, a
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/compiler/tests/composite_lit.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 21
6 | // @Test 1 2 = 24
7 | func main(a, b int32) int {
8 | arr := [3][2]int32{
9 | {1, 2},
10 | {3, 4},
11 | {5, 6},
12 | }
13 |
14 | var sum int32
15 | for i := 0; i < len(arr); i++ {
16 | sum += arr[i][0]
17 | sum += arr[i][1]
18 | }
19 |
20 | return sum + a + b
21 | }
22 |
--------------------------------------------------------------------------------
/compiler/tests/const_int.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 123
6 | func main(a, b int32) int {
7 | return 1 + 0x01 + 0b10 + 077 + 0o70
8 | }
9 |
--------------------------------------------------------------------------------
/compiler/tests/constmod.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 1
6 | func main(a, b int32) int2 {
7 | if 1%2 == 0 {
8 | return 0
9 | }
10 | return 1
11 | }
12 |
--------------------------------------------------------------------------------
/compiler/tests/copy_ptr.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type FieldElement [2]int32
6 |
7 | var zero FieldElement
8 |
9 | func FeZero(fe *FieldElement) {
10 | copy(fe[:], zero[:])
11 | }
12 |
13 | func FeOne(fe *FieldElement) {
14 | FeZero(fe)
15 | fe[0] = 1
16 | }
17 |
18 | type ProjectiveGroupElement struct {
19 | X, Y, Z FieldElement
20 | }
21 |
22 | func (p *ProjectiveGroupElement) Zero() {
23 | FeZero(&p.X)
24 | FeOne(&p.Y)
25 | FeOne(&p.Z)
26 | }
27 |
28 | // @Test 0 0 = 2
29 | func main(a, b int32) int {
30 | var pge ProjectiveGroupElement
31 |
32 | pge.Zero()
33 |
34 | return pge.X[0] + pge.Y[0] + pge.Z[0]
35 | }
36 |
--------------------------------------------------------------------------------
/compiler/tests/copy_slice_eq.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 45
6 | // @Test 1 2 = 48
7 | func main(a, b int32) int {
8 | var src [10]int32
9 | for i := 0; i < len(src); i++ {
10 | src[i] = i
11 | }
12 |
13 | var dst [10]int32
14 | copy(dst, src)
15 |
16 | var sum int32
17 | for i := 0; i < len(dst); i++ {
18 | sum += dst[i]
19 | }
20 |
21 | return a + b + sum
22 | }
23 |
--------------------------------------------------------------------------------
/compiler/tests/copy_slice_gt.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 10
6 | // @Test 1 2 = 13
7 | func main(a, b int32) int {
8 | var src [5]int32
9 | for i := 0; i < len(src); i++ {
10 | src[i] = i
11 | }
12 |
13 | var dst [10]int32
14 | copy(dst, src)
15 |
16 | var sum int32
17 | for i := 0; i < len(dst); i++ {
18 | sum += dst[i]
19 | }
20 |
21 | return a + b + sum
22 | }
23 |
--------------------------------------------------------------------------------
/compiler/tests/copy_slice_lt.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 10
6 | // @Test 1 2 = 13
7 | func main(a, b int32) int {
8 | var src [10]int32
9 | for i := 0; i < len(src); i++ {
10 | src[i] = i
11 | }
12 |
13 | var dst [5]int32
14 | copy(dst, src)
15 |
16 | var sum int32
17 | for i := 0; i < len(dst); i++ {
18 | sum += dst[i]
19 | }
20 |
21 | return a + b + sum
22 | }
23 |
--------------------------------------------------------------------------------
/compiler/tests/div.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 42
6 | // @Test 42 2 = 21
7 | // @Test 42 3 = 14
8 | // @Test 42 4 = 10
9 | // @Test 42 5 = 8
10 | // @Test 42 6 = 7
11 | // @Test 42 7 = 6
12 | // @Test 42 8 = 5
13 | // @Test 42 9 = 4
14 | // @Test 42 10 = 4
15 | // @Test 42 11 = 3
16 | // @Test 42 12 = 3
17 | // @Test 42 13 = 3
18 | // @Test 42 14 = 3
19 | // @Test 42 20 = 2
20 | // @Test 42 30 = 1
21 | // @Test 42 40 = 1
22 | // @Test 42 42 = 1
23 | // @Test 42 43 = 0
24 | func main(a, b uint64) uint64 {
25 | return a / b
26 | }
27 |
--------------------------------------------------------------------------------
/compiler/tests/for.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 10
6 | func main(a, b uint8) int32 {
7 | var sum int32 = 0
8 |
9 | for i := 0; i < 5; i = i + 1 {
10 | sum = sum + i
11 | }
12 |
13 | return sum
14 | }
15 |
--------------------------------------------------------------------------------
/compiler/tests/hmac_sha256.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/hmac"
7 | )
8 |
9 | // Test vectors from RFC-4231.
10 |
11 | // @Hex
12 | // @pprof
13 | // @LSB
14 | // @Test 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0x4869205468657265 = 0xb0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
15 | // @Test 0x4a656665 0x7768617420646f2079612077616e7420666f72206e6f7468696e673f = 0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
16 | // @Test 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd = 0x773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe
17 | // @Test 0x0102030405060708090a0b0c0d0e0f10111213141516171819 0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd = 0x82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b
18 | func main(key, data []byte) []byte {
19 | return hmac.SumSHA256(data, key)
20 | }
21 |
--------------------------------------------------------------------------------
/compiler/tests/len_array.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Field [10]int32
6 |
7 | // @Test 0 0 = 10
8 | func main(a, b int32) int {
9 | var arr Field
10 | return len(arr)
11 | }
12 |
--------------------------------------------------------------------------------
/compiler/tests/len_array_sum.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Field [10]int32
6 |
7 | // @Test 0 0 = 45
8 | // @Test 1 10 = 56
9 | func main(a, b int32) int {
10 | var arr Field
11 |
12 | for i := 0; i < len(arr); i++ {
13 | arr[i] = i
14 | }
15 |
16 | var sum int32
17 | for i := 0; i < len(arr); i++ {
18 | sum += arr[i]
19 | }
20 |
21 | return sum + a + b
22 | }
23 |
--------------------------------------------------------------------------------
/compiler/tests/len_string.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 13
6 | func main(a, b int32) int {
7 | val := "Hello, world!"
8 | return len(val)
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/len_string_sum.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 1161
6 | func main(a, b int32) int {
7 | val := "Hello, world!"
8 |
9 | var sum int32
10 | for i := 0; i < len(val); i++ {
11 | sum += int32(val[i])
12 | }
13 |
14 | return sum
15 | }
16 |
--------------------------------------------------------------------------------
/compiler/tests/lshift0.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 32
7 | func main(a, b uint64) uint64 {
8 | return a << 0
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/lshift1.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 64
7 | func main(a, b uint64) uint64 {
8 | return a << 1
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/lshift64.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 0
7 | func main(a, b uint64) uint64 {
8 | return a << 64
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/make.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 1 1 = 1
6 | // @Test 5 10 = 50
7 | func main(a, b int32) int {
8 | return mult(a, b)
9 | }
10 |
11 | func mult(a, b int) int {
12 | mType := make(int, size(a)*2)
13 |
14 | return mType(a) * mType(b)
15 | }
16 |
--------------------------------------------------------------------------------
/compiler/tests/mod.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 0
6 | // @Test 42 40 = 2
7 | // @Test 42 41 = 1
8 | // @Test 42 42 = 0
9 | // @Test 42 100 = 42
10 | func main(a, b uint64) uint64 {
11 | return a % b
12 | }
13 |
--------------------------------------------------------------------------------
/compiler/tests/mult.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 42
6 | // @Test 42 2 = 84
7 | // @Test 65536 0 = 0
8 | // @Test 65536 1 = 65536
9 | // @Test 65536 65536 = 4294967296
10 | // @Hex
11 | // @Test 0xff 0xff = 0xfe01
12 | // @Test 0xffff 0xff = 0xfeff01
13 | // @Test 0xff00 0x10 = 0xff000
14 | // @Test 0xff00 0x100 = 0xff0000
15 | // @Test 0xff 0xff = 0xfe01
16 | func main(a, b uint64) uint {
17 | return a * b
18 | }
19 |
--------------------------------------------------------------------------------
/compiler/tests/named_return.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func sum(a, b int32) (result int32) {
6 | result = a + b
7 | return
8 | }
9 |
10 | // @Test 1 2 = 3
11 | // @Test 55 66 = 121
12 | func main(a, b int32) int {
13 | return sum(a, b)
14 | }
15 |
--------------------------------------------------------------------------------
/compiler/tests/pkg.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "math"
7 | )
8 |
9 | const MaxUint64 = 42
10 |
11 | // @Test 0 0 = 42 0xffffffffffffffff
12 | func main(a, b uint64) (uint64, uint64) {
13 | return MaxUint64, math.MaxUint64
14 | }
15 |
--------------------------------------------------------------------------------
/compiler/tests/ptr.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func bar(val *int32) int {
6 | *val = int32(42)
7 | return 7
8 | }
9 |
10 | // @Test 0 0 = 49
11 | // @Test 1 2 = 52
12 | func main(a, b int32) int {
13 | var c int32
14 |
15 | sum := a + b
16 |
17 | sum += bar(&c)
18 |
19 | return sum + c
20 | }
21 |
--------------------------------------------------------------------------------
/compiler/tests/ptr_array.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type FieldElement [10]int32
6 |
7 | var zero FieldElement
8 |
9 | func FeZero(fe *FieldElement) {
10 | copy(fe[:], zero[:])
11 | }
12 |
13 | func FeOne(fe *FieldElement) {
14 | FeZero(fe)
15 | fe[0] = 1
16 | fe[1] = 0
17 | }
18 |
19 | // @Test 0 0 = 1
20 | // @Test 1 2 = 4
21 | func main(a, b int32) int {
22 | var v FieldElement
23 |
24 | FeOne(&v)
25 |
26 | return a + b + v[0]
27 | }
28 |
--------------------------------------------------------------------------------
/compiler/tests/ptr_array_get.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func sum(arr []int32) int32 {
6 | var sum int32
7 | for i := 0; i < len(arr); i++ {
8 | sum += arr[i]
9 | }
10 | return sum
11 | }
12 |
13 | func trampoline(a *[10]int32) int {
14 | return sum(a)
15 | }
16 |
17 | // @Test 0 0 = 0
18 | // @Test 1 0 = 5
19 | // @Test 1 2 = 15
20 | func main(a, b int32) int {
21 | var arr [10]int32
22 |
23 | for i := 0; i < len(arr); i++ {
24 | if i < len(arr)/2 {
25 | arr[i] = a
26 | } else {
27 | arr[i] = b
28 | }
29 | }
30 | return trampoline(&arr)
31 | }
32 |
--------------------------------------------------------------------------------
/compiler/tests/ptr_arrays.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | func Add(ptr *uint32, val uint32) {
6 | *ptr = val
7 | }
8 |
9 | // @Test 0 0 = 0
10 | // @Test 1 2 = 6
11 | // @Test 3 7 = 20
12 | func main(a, b uint32) uint {
13 | var sum [2][2]uint32
14 |
15 | Add(&sum[0][0], a)
16 | Add(&sum[0][1], a)
17 | Add(&sum[1][0], b)
18 | Add(&sum[1][1], b)
19 |
20 | return sum[0][0] + sum[0][1] + sum[1][0] + sum[1][1]
21 | }
22 |
--------------------------------------------------------------------------------
/compiler/tests/ptr_scopes.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | var c int32
6 |
7 | func set(ptr *int32, val int32) {
8 | *ptr = val
9 | }
10 |
11 | func setGlobal(val int32) {
12 | set(&c, val)
13 | }
14 |
15 | func getGlobal() int32 {
16 | return c
17 | }
18 |
19 | // @Test 0 0 = 0
20 | // @Test 1 2 = 3
21 | // @Test 7 9 = 16
22 | func main(a, b int32) int {
23 | var c int32
24 |
25 | set(&c, a)
26 | setGlobal(b)
27 |
28 | return c + getGlobal()
29 | }
30 |
--------------------------------------------------------------------------------
/compiler/tests/ptr_struct_field.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | type Foo struct {
6 | A int32
7 | B int32
8 | }
9 |
10 | func Set(ptr *int32, val int32) {
11 | *ptr = val
12 | }
13 |
14 | var f Foo
15 |
16 | // @Test 0 0 = 0
17 | // @Test 1 2 = 3
18 | // @Test 7 4 = 11
19 | func main(a, b int32) int {
20 | Set(&f.A, a)
21 | Set(&f.B, b)
22 |
23 | return f.A + f.B
24 | }
25 |
--------------------------------------------------------------------------------
/compiler/tests/rsa.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | import (
7 | "crypto/rsa"
8 | )
9 |
10 | // d: 0x321af139
11 | // n: 0xd60b2b09
12 | // e: 0x10001
13 | //
14 | // private: d, e
15 | // public: n, e
16 |
17 | // msg: 0x6d7472
18 | // cipher: 0x61f9ef88
19 |
20 | type Size = uint32
21 |
22 | type Garbler struct {
23 | msg Size
24 | privShare Size
25 | pubN Size
26 | pubE Size
27 | }
28 |
29 | // @Test 0x6d7472 0x321af130 0xd60b2b09 0x10001 9 = 0x55a83b79
30 | func main(g Garbler, privShare Size) uint {
31 |
32 | priv := g.privShare + privShare
33 |
34 | return rsa.Decrypt(g.msg, priv, g.pubN)
35 | }
36 |
--------------------------------------------------------------------------------
/compiler/tests/rshift0.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 32
7 | func main(a, b uint64) uint64 {
8 | return a >> 0
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/rshift1.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 16
7 | func main(a, b uint64) uint64 {
8 | return a >> 1
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/rshift64.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 32 0 = 0
7 | func main(a, b uint64) uint64 {
8 | return a >> 64
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/sha256_block.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha256"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0x1fd35a2a9e6f530dd6e5e87075c4d98ebb2960e2b65085cddeae2f65853a3af
11 | func main(g, e byte) []byte {
12 | var data [50]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha256.Sum256(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/sha256_block_block.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha256"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0xd650f570ed931e5cfe52bf339dd77493796f15e5c856a801efc90983e0bfa08b
11 | func main(g, e byte) []byte {
12 | var data [65]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha256.Sum256(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/sha256_block_pad.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha256"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0x130d73e5967c29157813960ae640447ffd228b8cb5dba6ba641ebeb3cef2e914
11 | func main(g, e byte) []byte {
12 | var data [60]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha256.Sum256(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/sha512_block.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha512"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0x257ebf75d3818e9de4f8b56f0272e452e8c9d6353ae9fbe284f950b3f79fc8027d171e0cb6e0029de0655a9ff90800db6574e25da5071a541f48a78b79514927
11 | func main(g, e byte) []byte {
12 | var data [110]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha512.Sum512(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/sha512_block_block.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha512"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0xeb627442f972d3df69591b22d8a26eadb115c1c82a3e00767c45e3776906f2fb70e487f9282a5193777579954b84e881dbaa1832960e66039678b771b81a704e
11 | func main(g, e byte) []byte {
12 | var data [129]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha512.Sum512(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/sha512_block_pad.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | import (
6 | "crypto/sha512"
7 | )
8 |
9 | // @Hex
10 | // @Test 0 0 = 0xb380cd63710ae12c7f743585889f243e02bb673124ac56b7548f636e57d2fb42aeff4a6d7acbb8f223b008e309e4756a14d70b7842df7ff8f442ca9504e3ff2c
11 | func main(g, e byte) []byte {
12 | var data [124]byte
13 | data[0] = 0x6d
14 | data[1] = 0x74
15 | data[2] = 0x72
16 | return sha512.Sum512(data[:])
17 | }
18 |
--------------------------------------------------------------------------------
/compiler/tests/slice.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 |
4 | package main
5 |
6 | // @Test 4294967295 0 = 255
7 | func main(a, b uint64) uint {
8 | return (a + b)[:8]
9 | }
10 |
--------------------------------------------------------------------------------
/compiler/tests/sub.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 1 = 41
6 | // @Test 42 40 = 2
7 | // @Test 42 41 = 1
8 | // @Test 42 42 = 0
9 | // @Test 1584886686 1584886686 = 0
10 | // @Test 1584886686 1584886680 = 6
11 | func main(a, b uint64) uint64 {
12 | return a - b
13 | }
14 |
--------------------------------------------------------------------------------
/compiler/tests/test_ge.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 11 = 1
6 | // @Test 42 42 = 1
7 | // @Test 42 43 = 0
8 | // @Test 42 0 = 1
9 | // @Test 0 0 = 1
10 | // @Test 0 42 = 0
11 | // @Test 42 0xffff = 0
12 | // @Test 0xffff 0xffff = 1
13 | // @Test 0xffff 42 = 1
14 | func main(a, b uint16) bool {
15 | return a >= b
16 | }
17 |
--------------------------------------------------------------------------------
/compiler/tests/test_gt.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 11 = 1
6 | // @Test 42 42 = 0
7 | // @Test 42 43 = 0
8 | // @Test 42 0 = 1
9 | // @Test 0 0 = 0
10 | // @Test 0 42 = 0
11 | // @Test 42 0xffff = 0
12 | // @Test 0xffff 0xffff = 0
13 | // @Test 0xffff 42 = 1
14 | func main(a, b uint16) bool {
15 | return a > b
16 | }
17 |
--------------------------------------------------------------------------------
/compiler/tests/test_le.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 11 = 0
6 | // @Test 42 42 = 1
7 | // @Test 42 43 = 1
8 | // @Test 42 0 = 0
9 | // @Test 0 0 = 1
10 | // @Test 0 42 = 1
11 | // @Test 42 0xffff = 1
12 | // @Test 0xffff 0xffff = 1
13 | // @Test 0xffff 42 = 0
14 | func main(a, b uint16) bool {
15 | return a <= b
16 | }
17 |
--------------------------------------------------------------------------------
/compiler/tests/test_lt.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 42 11 = 0
6 | // @Test 42 42 = 0
7 | // @Test 42 43 = 1
8 | // @Test 42 0 = 0
9 | // @Test 0 0 = 0
10 | // @Test 0 42 = 1
11 | // @Test 42 0xffff = 1
12 | // @Test 0xffff 0xffff = 0
13 | // @Test 0xffff 42 = 0
14 | func main(a, b uint16) bool {
15 | return a < b
16 | }
17 |
--------------------------------------------------------------------------------
/compiler/tests/var.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 0
6 | // @Test 1 2 = 3
7 | func main(a, b int32) int32 {
8 | var r int32
9 |
10 | r = a + b
11 |
12 | return r
13 | }
14 |
--------------------------------------------------------------------------------
/compiler/tests/var2.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 42
6 | // @Test 1 2 = 45
7 | func main(a, b int32) int32 {
8 | var r int32 = 42
9 |
10 | r = r + a + b
11 |
12 | return r
13 | }
14 |
--------------------------------------------------------------------------------
/compiler/tests/var3.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | var base uint32 = 42
6 |
7 | // @Test 0 0 = 42
8 | // @Test 1 2 = 45
9 | func main(a, b uint32) uint {
10 | return base + a + b
11 | }
12 |
--------------------------------------------------------------------------------
/compiler/tests/zerolabel.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 |
3 | package main
4 |
5 | // @Test 0 0 = 2
6 | func main(a, b uint2) uint {
7 | var r uint2 = 1 // init 1 bugs, 0 works.
8 |
9 | r = r * 1
10 | r = r + 1
11 |
12 | return r
13 | }
14 |
--------------------------------------------------------------------------------
/compiler/utils/logger.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package utils
8 |
9 | import (
10 | "errors"
11 | "fmt"
12 | "io"
13 | "strings"
14 | )
15 |
16 | // Logger implements compiler logging facility.
17 | type Logger struct {
18 | out io.Writer
19 | }
20 |
21 | // NewLogger creates a new logger outputting to the argument io.Writer.
22 | func NewLogger(out io.Writer) *Logger {
23 | return &Logger{
24 | out: out,
25 | }
26 | }
27 |
28 | // Errorf logs an error message.
29 | func (l *Logger) Errorf(loc Point, format string, a ...interface{}) error {
30 | msg := fmt.Sprintf(format, a...)
31 | if len(msg) > 0 && msg[len(msg)-1] != '\n' {
32 | msg += "\n"
33 | }
34 | if loc.Undefined() {
35 | fmt.Fprintf(l.out, "%s: %s", loc.Source, msg)
36 | } else {
37 | fmt.Fprintf(l.out, "%s: %s", loc, msg)
38 | }
39 |
40 | idx := strings.IndexRune(msg, '\n')
41 | if idx > 0 {
42 | msg = msg[:idx]
43 | }
44 | return errors.New(msg)
45 | }
46 |
47 | // Warningf logs a warning message.
48 | func (l *Logger) Warningf(loc Point, format string, a ...interface{}) {
49 | msg := fmt.Sprintf(format, a...)
50 | if len(msg) > 0 && msg[len(msg)-1] != '\n' {
51 | msg += "\n"
52 | }
53 | if loc.Undefined() {
54 | fmt.Fprintf(l.out, "%s: warning: %s", loc.Source, msg)
55 | } else {
56 | fmt.Fprintf(l.out, "%s: warning: %s", loc, msg)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/compiler/utils/params.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2022 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package utils
8 |
9 | import (
10 | "io"
11 | )
12 |
13 | // Params specify compiler parameters.
14 | type Params struct {
15 | Verbose bool
16 | Diagnostics bool
17 | SSAOut io.WriteCloser
18 | SSADotOut io.WriteCloser
19 |
20 | // MaxVarBits specifies the maximum variable width in bits.
21 | MaxVarBits int
22 |
23 | // MaxLoopUnroll specifies the upper limit for loop unrolling.
24 | MaxLoopUnroll int
25 |
26 | NoCircCompile bool
27 | CircOut io.WriteCloser
28 | CircDotOut io.WriteCloser
29 | CircSvgOut io.WriteCloser
30 | CircFormat string
31 |
32 | CircMultArrayTreshold int
33 |
34 | OptPruneGates bool
35 | }
36 |
37 | // NewParams returns new compiler params object, initialized with the
38 | // default values.
39 | func NewParams() *Params {
40 | return &Params{
41 | MaxVarBits: 0x20000,
42 | MaxLoopUnroll: 0x20000,
43 | }
44 | }
45 |
46 | // Close closes all open resources.
47 | func (p *Params) Close() {
48 | if p.SSAOut != nil {
49 | p.SSAOut.Close()
50 | p.SSAOut = nil
51 | }
52 | if p.SSADotOut != nil {
53 | p.SSADotOut.Close()
54 | p.SSADotOut = nil
55 | }
56 | if p.CircOut != nil {
57 | p.CircOut.Close()
58 | p.CircOut = nil
59 | }
60 | if p.CircDotOut != nil {
61 | p.CircDotOut.Close()
62 | p.CircDotOut = nil
63 | }
64 | if p.CircSvgOut != nil {
65 | p.CircSvgOut.Close()
66 | p.CircSvgOut = nil
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/compiler/utils/point.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2021 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package utils
8 |
9 | import (
10 | "fmt"
11 | )
12 |
13 | // Locator is an interface that implements Location method for
14 | // returning item's input data position.
15 | type Locator interface {
16 | Location() Point
17 | }
18 |
19 | // Point specifies a position in the compiler input data.
20 | type Point struct {
21 | Source string
22 | Line int // 1-based
23 | Col int // 0-based
24 | }
25 |
26 | // Location implements the Locator interface.
27 | func (p Point) Location() Point {
28 | return p
29 | }
30 |
31 | func (p Point) String() string {
32 | return fmt.Sprintf("%s:%d:%d", p.Source, p.Line, p.Col)
33 | }
34 |
35 | // Undefined tests if the input position is undefined.
36 | func (p Point) Undefined() bool {
37 | return p.Line == 0
38 | }
39 |
--------------------------------------------------------------------------------
/compiler/utils/point_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020-2021 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package utils
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | func TestPoint(t *testing.T) {
14 | p := Point{}
15 | if !p.Undefined() {
16 | t.Errorf("undefined point is not undefined")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module source.quilibrium.com/quilibrium/monorepo/bedlam
2 |
3 | go 1.20
4 |
5 | // A necessary hack until source.quilibrium.com is open to all
6 | replace source.quilibrium.com/quilibrium/monorepo/nekryptology => ../nekryptology
7 |
8 | require (
9 | github.com/btcsuite/btcd/btcec/v2 v2.3.2
10 | source.quilibrium.com/quilibrium/monorepo/nekryptology v0.0.0-00010101000000-000000000000
11 | )
12 |
13 | require github.com/pkg/errors v0.9.1 // indirect
14 |
15 | require (
16 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
17 | golang.org/x/exp v0.0.0-20231006140011-7918f672742d
18 | )
19 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
2 | github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
3 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
4 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
5 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
6 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
7 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
8 | golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
9 | golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
10 |
--------------------------------------------------------------------------------
/ot/README.md:
--------------------------------------------------------------------------------
1 | # Oblivious Transfer
2 |
3 | This module implements the Oblivous Transfer with the following
4 | algorithms:
5 |
6 | - RSA: simple RSA encryption based OT. Each transfer requires one RSA
7 | operation.
8 | - Chou Orlandi OT: Diffie-Hellman - like fast OT algorithm.
9 |
10 | ## Performance
11 |
12 | | Algorithm | ns/op | ops/s |
13 | | :----------- | ---------: | ------: |
14 | | RSA-512 | 252557 | 3960 |
15 | | RSA-1024 | 1256961 | 796 |
16 | | RSA-2048 | 7785958 | 128 |
17 | | CO-batch-1 | 170791 | 5855 |
18 | | CO-batch-2 | 269399 | 7424 |
19 | | CO-batch-4 | 468161 | 8544 |
20 | | CO-batch-8 | 877664 | 9115 |
21 | | CO-batch-16 | 1706184 | 9378 |
22 | | CO-batch-32 | 3273137 | 9777 |
23 | | CO-batch-64 | 6480310 | 9876 |
24 | | CO-batch-128 | 12845639 | 9964 |
25 |
26 | Ferret enablement is not included in the public devkit preview
--------------------------------------------------------------------------------
/ot/co_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // rsa_test.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package ot
10 |
11 | import (
12 | "bytes"
13 | "crypto/rand"
14 | "testing"
15 | )
16 |
17 | func TestCO(t *testing.T) {
18 | l0, _ := NewLabel(rand.Reader)
19 | l1, _ := NewLabel(rand.Reader)
20 |
21 | sender := NewCOSender()
22 | receiver := NewCOReceiver(sender.Curve())
23 |
24 | var l0Buf, l1Buf LabelData
25 | l0Data := l0.Bytes(&l0Buf)
26 | l1Data := l1.Bytes(&l1Buf)
27 |
28 | sXfer, err := sender.NewTransfer(l0Data, l1Data)
29 | if err != nil {
30 | t.Fatalf("COSender.NewTransfer: %v", err)
31 | }
32 | var bit uint = 1
33 |
34 | rXfer, err := receiver.NewTransfer(bit)
35 | if err != nil {
36 | t.Fatalf("COReceiver.NewTransfer: %v", err)
37 | }
38 | rXfer.ReceiveA(sXfer.A())
39 | sXfer.ReceiveB(rXfer.B())
40 | result := rXfer.ReceiveE(sXfer.E())
41 |
42 | var ret int
43 | if bit == 0 {
44 | ret = bytes.Compare(result, l0Data[:])
45 | } else {
46 | ret = bytes.Compare(result, l1Data[:])
47 | }
48 | if ret != 0 {
49 | t.Errorf("Verify failed")
50 | }
51 | }
52 |
53 | func BenchmarkCO(b *testing.B) {
54 | l0, _ := NewLabel(rand.Reader)
55 | l1, _ := NewLabel(rand.Reader)
56 |
57 | sender := NewCOSender()
58 | receiver := NewCOReceiver(sender.Curve())
59 |
60 | b.ResetTimer()
61 |
62 | var l0Buf, l1Buf LabelData
63 | for i := 0; i < b.N; i++ {
64 | l0Data := l0.Bytes(&l0Buf)
65 | l1Data := l1.Bytes(&l1Buf)
66 | sXfer, err := sender.NewTransfer(l0Data, l1Data)
67 | if err != nil {
68 | b.Fatalf("COSender.NewTransfer: %v", err)
69 | }
70 | bit := uint(i % 2)
71 |
72 | rXfer, err := receiver.NewTransfer(bit)
73 | if err != nil {
74 | b.Fatalf("COReceiver.NewTransfer: %v", err)
75 | }
76 | rXfer.ReceiveA(sXfer.A())
77 | sXfer.ReceiveB(rXfer.B())
78 | result := rXfer.ReceiveE(sXfer.E())
79 |
80 | var ret int
81 | if bit == 0 {
82 | ret = bytes.Compare(l0Data[:], result)
83 | } else {
84 | ret = bytes.Compare(l1Data[:], result)
85 | }
86 | if ret != 0 {
87 | b.Fatal("Verify failed")
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/ot/io.go:
--------------------------------------------------------------------------------
1 | //
2 | // io.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 |
8 | package ot
9 |
10 | import (
11 | "math/big"
12 | )
13 |
14 | // IO defines an I/O interface to communicate between peers.
15 | type IO interface {
16 | // SendData sends binary data.
17 | SendData(val []byte) error
18 |
19 | // SendUint32 sends an uint32 value.
20 | SendUint32(val int) error
21 |
22 | // Flush flushed any pending data in the connection.
23 | Flush() error
24 |
25 | // ReceiveData receives binary data.
26 | ReceiveData() ([]byte, error)
27 |
28 | // ReceiveUint32 receives an uint32 value.
29 | ReceiveUint32() (int, error)
30 | }
31 |
32 | // SendString sends a string value.
33 | func SendString(io IO, str string) error {
34 | return io.SendData([]byte(str))
35 | }
36 |
37 | // ReceiveString receives a string value.
38 | func ReceiveString(io IO) (string, error) {
39 | data, err := io.ReceiveData()
40 | if err != nil {
41 | return "", err
42 | }
43 | return string(data), nil
44 | }
45 |
46 | // ReceiveBigInt receives a bit.Int from the connection.
47 | func ReceiveBigInt(io IO) (*big.Int, error) {
48 | data, err := io.ReceiveData()
49 | if err != nil {
50 | return nil, err
51 | }
52 | return big.NewInt(0).SetBytes(data), nil
53 | }
54 |
--------------------------------------------------------------------------------
/ot/label.go:
--------------------------------------------------------------------------------
1 | //
2 | // label.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package ot
10 |
11 | import (
12 | "encoding/binary"
13 | "fmt"
14 | "io"
15 | )
16 |
17 | // Wire implements a wire with 0 and 1 labels.
18 | type Wire struct {
19 | L0 Label
20 | L1 Label
21 | }
22 |
23 | // Label implements a 128 bit wire label.
24 | type Label struct {
25 | D0 uint64
26 | D1 uint64
27 | }
28 |
29 | // LabelData contains lable data as byte array.
30 | type LabelData [16]byte
31 |
32 | func (l Label) String() string {
33 | return fmt.Sprintf("%016x%016x", l.D0, l.D1)
34 | }
35 |
36 | // Equal test if the labels are equal.
37 | func (l Label) Equal(o Label) bool {
38 | return l.D0 == o.D0 && l.D1 == o.D1
39 | }
40 |
41 | // NewLabel creates a new random label.
42 | func NewLabel(rand io.Reader) (Label, error) {
43 | var buf LabelData
44 | var label Label
45 |
46 | if _, err := rand.Read(buf[:]); err != nil {
47 | return label, err
48 | }
49 | label.SetData(&buf)
50 | return label, nil
51 | }
52 |
53 | // NewTweak creates a new label from the tweak value.
54 | func NewTweak(tweak uint32) Label {
55 | return Label{
56 | D1: uint64(tweak),
57 | }
58 | }
59 |
60 | // S tests the label's S bit.
61 | func (l Label) S() bool {
62 | return (l.D0 & 0x8000000000000000) != 0
63 | }
64 |
65 | // SetS sets the label's S bit.
66 | func (l *Label) SetS(set bool) {
67 | if set {
68 | l.D0 |= 0x8000000000000000
69 | } else {
70 | l.D0 &= 0x7fffffffffffffff
71 | }
72 | }
73 |
74 | // Mul2 multiplies the label by 2.
75 | func (l *Label) Mul2() {
76 | l.D0 <<= 1
77 | l.D0 |= (l.D1 >> 63)
78 | l.D1 <<= 1
79 | }
80 |
81 | // Mul4 multiplies the label by 4.
82 | func (l *Label) Mul4() {
83 | l.D0 <<= 2
84 | l.D0 |= (l.D1 >> 62)
85 | l.D1 <<= 2
86 | }
87 |
88 | // Xor xors the label with the argument label.
89 | func (l *Label) Xor(o Label) {
90 | l.D0 ^= o.D0
91 | l.D1 ^= o.D1
92 | }
93 |
94 | // GetData gets the labels as label data.
95 | func (l Label) GetData(buf *LabelData) {
96 | binary.BigEndian.PutUint64(buf[0:8], l.D0)
97 | binary.BigEndian.PutUint64(buf[8:16], l.D1)
98 | }
99 |
100 | // SetData sets the labels from label data.
101 | func (l *Label) SetData(data *LabelData) {
102 | l.D0 = binary.BigEndian.Uint64((*data)[0:8])
103 | l.D1 = binary.BigEndian.Uint64((*data)[8:16])
104 | }
105 |
106 | // Bytes returns the label data as bytes.
107 | func (l Label) Bytes(buf *LabelData) []byte {
108 | l.GetData(buf)
109 | return buf[:]
110 | }
111 |
112 | // SetBytes sets the label data from bytes.
113 | func (l *Label) SetBytes(data []byte) {
114 | l.D0 = binary.BigEndian.Uint64(data[0:8])
115 | l.D1 = binary.BigEndian.Uint64(data[8:16])
116 | }
117 |
--------------------------------------------------------------------------------
/ot/label_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // label_test.go
3 | //
4 | // Copyright (c) 2019-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package ot
10 |
11 | import (
12 | "testing"
13 | )
14 |
15 | func BenchmarkLabelMul2(b *testing.B) {
16 | var l Label
17 |
18 | for i := 0; i < b.N; i++ {
19 | l.Mul2()
20 | }
21 | }
22 |
23 | func BenchmarkLabelMul4(b *testing.B) {
24 | var l Label
25 |
26 | for i := 0; i < b.N; i++ {
27 | l.Mul4()
28 | }
29 | }
30 |
31 | func BenchmarkLabelXor(b *testing.B) {
32 | var l0, l1 Label
33 |
34 | for i := 0; i < b.N; i++ {
35 | l0.Xor(l1)
36 | }
37 | }
38 |
39 | func TestLabel(t *testing.T) {
40 | label := &Label{
41 | D0: 0xffffffffffffffff,
42 | D1: 0xffffffffffffffff,
43 | }
44 |
45 | label.SetS(true)
46 | if label.D0 != 0xffffffffffffffff {
47 | t.Fatal("Failed to set S-bit")
48 | }
49 |
50 | label.SetS(false)
51 | if label.D0 != 0x7fffffffffffffff {
52 | t.Fatalf("Failed to clear S-bit: %x", label.D0)
53 | }
54 |
55 | label = &Label{
56 | D1: 0xffffffffffffffff,
57 | }
58 | label.Mul2()
59 | if label.D0 != 0x1 {
60 | t.Fatalf("Mul2 D0 failed")
61 | }
62 | if label.D1 != 0xfffffffffffffffe {
63 | t.Fatalf("Mul2 D1 failed: %x", label.D1)
64 | }
65 |
66 | label = &Label{
67 | D1: 0xffffffffffffffff,
68 | }
69 | label.Mul4()
70 | if label.D0 != 0x3 {
71 | t.Fatalf("Mul4 D0 failed")
72 | }
73 | if label.D1 != 0xfffffffffffffffc {
74 | t.Fatalf("Mul4 D1 failed")
75 | }
76 |
77 | val := uint64(0x5555555555555555)
78 | label = &Label{
79 | D0: val,
80 | D1: val << 1,
81 | }
82 | label.Xor(Label{
83 | D0: 0xffffffffffffffff,
84 | D1: 0xffffffffffffffff,
85 | })
86 | if label.D0 != val<<1 {
87 | t.Errorf("Xor failed: D0=%x, expected=%x", label.D0, val<<1)
88 | }
89 | if label.D1 != val {
90 | t.Errorf("Xor failed: D1=%x, expected=%x", label.D1, val)
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/ot/mpint/mpint.go:
--------------------------------------------------------------------------------
1 | //
2 | // mpint.go
3 | //
4 | // Copyright (c) 2019 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package mpint
10 |
11 | import (
12 | "math/big"
13 | )
14 |
15 | // FromBytes creates a big.Int from the data.
16 | func FromBytes(data []byte) *big.Int {
17 | return big.NewInt(0).SetBytes(data)
18 | }
19 |
20 | // Add adds two big.Int numbers and returns the result as a new
21 | // big.Int.
22 | func Add(a, b *big.Int) *big.Int {
23 | return big.NewInt(0).Add(a, b)
24 | }
25 |
26 | // Sub subtracts two big.Int numbers and returns the result as a new
27 | // big.Int.
28 | func Sub(a, b *big.Int) *big.Int {
29 | return big.NewInt(0).Sub(a, b)
30 | }
31 |
32 | // Exp computes x^y MOD m and returns the result as a new big.Int.
33 | func Exp(x, y, m *big.Int) *big.Int {
34 | return big.NewInt(0).Exp(x, y, m)
35 | }
36 |
37 | // Mod computes x%y and returns the result as a new big.Int.
38 | func Mod(x, y *big.Int) *big.Int {
39 | return big.NewInt(0).Mod(x, y)
40 | }
41 |
--------------------------------------------------------------------------------
/ot/mpint/mpint_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // mpint_test.go
3 | //
4 | // Copyright (c) 2019 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package mpint
10 |
11 | import (
12 | "testing"
13 | )
14 |
15 | var (
16 | oneData = []byte{0x1}
17 | twoData = []byte{0x2}
18 | threeData = []byte{0x3}
19 | )
20 |
21 | func TestMPInt(t *testing.T) {
22 | one := FromBytes(oneData)
23 | two := FromBytes(twoData)
24 | three := FromBytes(threeData)
25 |
26 | sum := Add(one, two)
27 | if sum.Cmp(three) != 0 {
28 | t.Errorf("%s + %s = %s, expected %s\n", one, two, sum, three)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ot/ot.go:
--------------------------------------------------------------------------------
1 | //
2 | // ot.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 |
8 | package ot
9 |
10 | // OT defines Oblivious Transfer protocol.
11 | type OT interface {
12 | // InitSender initializes the OT sender.
13 | InitSender(io IO) error
14 |
15 | // InitReceiver initializes the OT receiver.
16 | InitReceiver(io IO) error
17 |
18 | // Send sends the wire labels with OT.
19 | Send(wires []Wire) error
20 |
21 | // Receive receives the wire labels with OT based on the flag values.
22 | Receive(flags []bool, result []Label) error
23 | }
24 |
--------------------------------------------------------------------------------
/ot/pipe.go:
--------------------------------------------------------------------------------
1 | //
2 | // pipe.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 |
8 | package ot
9 |
10 | import (
11 | "fmt"
12 | "io"
13 | )
14 |
15 | var (
16 | _ IO = &Pipe{}
17 | )
18 |
19 | // Pipe implements the IO interface with in-memory io.Pipe.
20 | type Pipe struct {
21 | rBuf []byte
22 | wBuf []byte
23 | r *io.PipeReader
24 | w *io.PipeWriter
25 | }
26 |
27 | // NewPipe creates a new in-memory pipe.
28 | func NewPipe() (*Pipe, *Pipe) {
29 | ar, aw := io.Pipe()
30 | br, bw := io.Pipe()
31 |
32 | return &Pipe{
33 | rBuf: make([]byte, 64*1024),
34 | wBuf: make([]byte, 64*1024),
35 | r: ar,
36 | w: bw,
37 | }, &Pipe{
38 | rBuf: make([]byte, 64*1024),
39 | wBuf: make([]byte, 64*1024),
40 | r: br,
41 | w: aw,
42 | }
43 | }
44 |
45 | // SendData sends binary data.
46 | func (p *Pipe) SendData(val []byte) error {
47 | l := len(val)
48 | bo.PutUint32(p.wBuf, uint32(l))
49 | n := copy(p.wBuf[4:], val)
50 | if n != l {
51 | return fmt.Errorf("pipe buffer too short: %d > %d", l, len(p.wBuf))
52 | }
53 | _, err := p.w.Write(p.wBuf[:4+l])
54 | return err
55 | }
56 |
57 | // SendUint32 sends an uint32 value.
58 | func (p *Pipe) SendUint32(val int) error {
59 | bo.PutUint32(p.wBuf, uint32(val))
60 | _, err := p.w.Write(p.wBuf[:4])
61 | return err
62 | }
63 |
64 | // Flush flushed any pending data in the connection.
65 | func (p *Pipe) Flush() error {
66 | return nil
67 | }
68 |
69 | // Drain consumes all input from the pipe.
70 | func (p *Pipe) Drain() error {
71 | _, err := io.Copy(io.Discard, p.r)
72 | return err
73 | }
74 |
75 | // Close closes the pipe.
76 | func (p *Pipe) Close() error {
77 | return p.w.Close()
78 | }
79 |
80 | // ReceiveData receives binary data.
81 | func (p *Pipe) ReceiveData() ([]byte, error) {
82 | _, err := p.r.Read(p.rBuf[:4])
83 | if err != nil {
84 | return nil, err
85 | }
86 | l := bo.Uint32(p.rBuf)
87 | if l > uint32(len(p.rBuf)) {
88 | return nil, fmt.Errorf("pipe buffer too short: %d > %d", l, len(p.rBuf))
89 | }
90 | n, err := p.r.Read(p.rBuf[:])
91 | return p.rBuf[:n], err
92 | }
93 |
94 | // ReceiveUint32 receives an uint32 value.
95 | func (p *Pipe) ReceiveUint32() (int, error) {
96 | _, err := p.r.Read(p.rBuf[:4])
97 | if err != nil {
98 | return 0, err
99 | }
100 | return int(bo.Uint32(p.rBuf)), nil
101 | }
102 |
--------------------------------------------------------------------------------
/ot/pipe_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // pipe_test.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package ot
10 |
11 | import (
12 | "bytes"
13 | "fmt"
14 | "io"
15 | "testing"
16 | )
17 |
18 | func TestPipe(t *testing.T) {
19 | testData := []byte("Hello, world!")
20 | testInt := 42
21 |
22 | pipe, rPipe := NewPipe()
23 | done := make(chan error)
24 |
25 | go func(pipe *Pipe) {
26 | data, err := pipe.ReceiveData()
27 | if err != nil {
28 | done <- err
29 | pipe.Close()
30 | return
31 | }
32 | if bytes.Compare(data, testData) != 0 {
33 | done <- fmt.Errorf("ReceiveData: value mismatch: %x != %x",
34 | data, testData)
35 | pipe.Close()
36 | return
37 | }
38 | v, err := pipe.ReceiveUint32()
39 | if err != nil {
40 | done <- err
41 | pipe.Close()
42 | return
43 | }
44 | if v != testInt {
45 | done <- fmt.Errorf("ReceiveUint32: value mismatch")
46 | pipe.Close()
47 | return
48 | }
49 | _, err = pipe.ReceiveUint32()
50 | if err != io.EOF {
51 | done <- fmt.Errorf("expected EOF")
52 | }
53 | done <- nil
54 | }(rPipe)
55 |
56 | err := pipe.SendData(testData)
57 | if err != nil {
58 | t.Errorf("SendData failed: %v", err)
59 | }
60 | err = pipe.SendUint32(testInt)
61 | if err != nil {
62 | t.Errorf("SendUint32 failed: %v", err)
63 | }
64 | err = pipe.Close()
65 | if err != nil {
66 | t.Errorf("Close failed: %v", err)
67 | }
68 |
69 | err = <-done
70 | if err != nil {
71 | t.Errorf("consumer failed: %v", err)
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/p2p/protocol_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // protocol_test.go
3 | //
4 | // Copyright (c) 2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package p2p
10 |
11 | import (
12 | "fmt"
13 | "io"
14 | "testing"
15 | )
16 |
17 | type pipe struct {
18 | r *io.PipeReader
19 | w *io.PipeWriter
20 | }
21 |
22 | func (p *pipe) Close() error {
23 | if err := p.r.Close(); err != nil {
24 | return err
25 | }
26 | return p.w.Close()
27 | }
28 |
29 | func (p *pipe) Read(data []byte) (n int, err error) {
30 | return p.r.Read(data)
31 | }
32 |
33 | func (p *pipe) Write(data []byte) (n int, err error) {
34 | return p.w.Write(data)
35 | }
36 |
37 | func newPipes() (*pipe, *pipe) {
38 | var p0, p1 pipe
39 |
40 | p0.r, p1.w = io.Pipe()
41 | p1.r, p0.w = io.Pipe()
42 |
43 | return &p0, &p1
44 | }
45 |
46 | var tests = []interface{}{
47 | byte(42),
48 | uint16(43),
49 | uint32(44),
50 | "Hello, world!",
51 | }
52 |
53 | func writer(c *Conn) {
54 | for _, test := range tests {
55 | switch d := test.(type) {
56 | case byte:
57 | if err := c.SendByte(d); err != nil {
58 | fmt.Printf("SendByte: %v\n", err)
59 | }
60 |
61 | case uint16:
62 | if err := c.SendUint16(int(d)); err != nil {
63 | fmt.Printf("SendUint16: %v\n", err)
64 | }
65 |
66 | case uint32:
67 | if err := c.SendUint32(int(d)); err != nil {
68 | fmt.Printf("SendUint32: %v\n", err)
69 | }
70 |
71 | case string:
72 | if err := c.SendString(d); err != nil {
73 | fmt.Printf("SendString: %v\n", err)
74 | }
75 |
76 | default:
77 | fmt.Printf("writer: invalid data: %v(%T)\n", test, test)
78 | }
79 | }
80 | if err := c.Flush(); err != nil {
81 | fmt.Printf("Flush: %v\n", err)
82 | }
83 | }
84 |
85 | func TestProtocol(t *testing.T) {
86 | p0, p1 := newPipes()
87 |
88 | go writer(NewConn(p0))
89 |
90 | c := NewConn(p1)
91 |
92 | for _, test := range tests {
93 | switch d := test.(type) {
94 | case byte:
95 | v, err := c.ReceiveByte()
96 | if err != nil {
97 | t.Fatalf("ReceiveByte: %v", err)
98 | }
99 | if v != d {
100 | t.Errorf("ReceiveByte: got %v, expected %v", v, d)
101 | }
102 |
103 | case uint16:
104 | v, err := c.ReceiveUint16()
105 | if err != nil {
106 | t.Fatalf("ReceiveUint16: %v", err)
107 | }
108 | if v != int(d) {
109 | t.Errorf("ReceiveUint16: got %v, expected %v", v, d)
110 | }
111 |
112 | case uint32:
113 | v, err := c.ReceiveUint32()
114 | if err != nil {
115 | t.Fatalf("ReceiveUint32: %v", err)
116 | }
117 | if v != int(d) {
118 | t.Errorf("ReceiveUint32: got %v, expected %v", v, d)
119 | }
120 |
121 | case string:
122 | v, err := c.ReceiveString()
123 | if err != nil {
124 | t.Fatalf("ReceiveString: %v", err)
125 | }
126 | if v != d {
127 | t.Errorf("ReceiveString: got %v, expected %v", v, d)
128 | }
129 |
130 | default:
131 | t.Errorf("invalid value: %v(%T)", test, test)
132 | }
133 | }
134 | if err := c.Close(); err != nil {
135 | t.Errorf("Close: %v", err)
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/pkg/builtin.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package builtin defines QCL builtin functions and types. This
9 | // package is always imported and the functions and types can be used
10 | // in all programs.
11 | package builtin
12 |
13 | // bool is a boolean value true or false.
14 | type bool bool
15 |
16 | // byte is an alias for unsigned 8-bit integer numbers.
17 | type byte = uint8
18 |
19 | // rune is an alias for int32.
20 | type rune = int32
21 |
22 | // intSize is a Size-bit signed integer number. The signed integer
23 | // numbers can be instantiated in any bit sizes.
24 | type intSize int
25 |
26 | // uintSize is a Size-bit unsigned integer number. The unsigned
27 | // integer numbers can be instantiated in any bit sizes.
28 | type uintSize uint
29 |
30 | // stringSize defines Size-bit long string.
31 | type stringSize string
32 |
33 | func copy(dst, src []Type) int32 {}
34 |
35 | // The floorPow2 built-in function returns the power of 2 number that
36 | // is smaller than or equal to the argument value.
37 | func floorPow2(v int) int {}
38 |
39 | // The len built-in function returns the length of the argument value,
40 | // according to its type:
41 | //
42 | // Array: the number of elements in the array
43 | // String: the number of bytes in the string
44 | func len(v Type) int32 {}
45 |
46 | // The native built-in function loads native circuit from the named
47 | // file. The circuit must be located in the same directory as the
48 | // calling QCL script. The native built-in function supports the
49 | // following circuit formats:
50 | //
51 | // .circ Bristol circuit format
52 | // .qclc compiled QCL circuit format
53 | func native(name string) []Type {}
54 |
55 | // The size built-in function returns the size of the argument value
56 | // in bits. The argument value can be of any type.
57 | func size(v Type) int32 {}
58 |
--------------------------------------------------------------------------------
/pkg/bytes/bytes.go:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package bytes
9 |
10 | // Compare compares two byte slices lexicographically. The result is 0
11 | // if a == b, -1 if a < b, and +1 if a > b.
12 | func Compare(a, b []byte) int {
13 | limit := len(a)
14 | if len(b) < limit {
15 | limit = len(b)
16 | }
17 | for i := 0; i < limit; i++ {
18 | if a[i] < b[i] {
19 | return -1
20 | }
21 | if a[i] > b[i] {
22 | return 1
23 | }
24 | }
25 | if len(a) < len(b) {
26 | return -1
27 | }
28 | if len(a) > len(b) {
29 | return 1
30 | }
31 | return 0
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/bytes/bytes.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package bytes
9 |
10 | // Compare compares two byte slices lexicographically. The result is 0
11 | // if a == b, -1 if a < b, and +1 if a > b.
12 | func Compare(a, b []byte) int {
13 | limit := len(a)
14 | if len(b) < limit {
15 | limit = len(b)
16 | }
17 | for i := 0; i < limit; i++ {
18 | if a[i] < b[i] {
19 | return -1
20 | }
21 | if a[i] > b[i] {
22 | return 1
23 | }
24 | }
25 | if len(a) < len(b) {
26 | return -1
27 | }
28 | if len(a) > len(b) {
29 | return 1
30 | }
31 | return 0
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/bytes/doc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package bytes implements functions for byte slice manipulation.
9 | package bytes
10 |
--------------------------------------------------------------------------------
/pkg/crypto/aes/cipher.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package aes implements the Advanced Encryption Standard (AES)
9 | // block cipher operations.
10 | package aes
11 |
12 | // BlockSize defines the AES cipher block size in bytes.
13 | const BlockSize = 16
14 |
15 | // EncryptBlock encrypts one data block with the key. The key must be
16 | // 16, 24, or 32 bytes long.
17 | func EncryptBlock(key []byte, data [BlockSize]byte) [BlockSize]byte {
18 | enc := ExpandEncryptionKey(key)
19 |
20 | var dst [BlockSize]byte
21 |
22 | return EncryptBlockExpanded(enc, dst, data)
23 | }
24 |
25 | // DecryptBlock decrypts one data block with the key. The key must be
26 | // 16, 24, or 32 bytes long.
27 | func DecryptBlock(key []byte, data [BlockSize]byte) [BlockSize]byte {
28 | enc, dec := ExpandKey(key)
29 |
30 | var dst [BlockSize]byte
31 |
32 | return DecryptBlockExpanded(dec, dst, data)
33 | }
34 |
--------------------------------------------------------------------------------
/pkg/crypto/aes/circuit.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package aes
9 |
10 | // Block128 encrypts one data block with 128 bit key.
11 | func Block128(key [16]byte, data [16]byte) [16]byte {
12 | var k uint128
13 | var d uint128
14 |
15 | for i := 0; i < len(key); i++ {
16 | k <<= 8
17 | k |= uint128(key[i])
18 | }
19 | for i := 0; i < len(data); i++ {
20 | d <<= 8
21 | d |= uint128(data[i])
22 | }
23 |
24 | c := block128(k, d)
25 | var cipher [16]byte
26 | for i := len(cipher) - 1; i >= 0; i-- {
27 | cipher[i] = c & 0xff
28 | c >>= 8
29 | }
30 | return cipher
31 | }
32 |
33 | // Block192 encrypts one data block with 192 bit key.
34 | func Block192(key [24]byte, data [16]byte) [16]byte {
35 | var k uint192
36 | var d uint128
37 |
38 | for i := 0; i < len(key); i++ {
39 | k <<= 8
40 | k |= uint192(key[i])
41 | }
42 | for i := 0; i < len(data); i++ {
43 | d <<= 8
44 | d |= uint128(data[i])
45 | }
46 |
47 | c := block192(k, d)
48 | var cipher [16]byte
49 | for i := len(cipher) - 1; i >= 0; i-- {
50 | cipher[i] = c & 0xff
51 | c >>= 8
52 | }
53 | return cipher
54 | }
55 |
56 | // Block256 encrypts one data block with 256 bit key.
57 | func Block256(key [32]byte, data [16]byte) [16]byte {
58 | var k uint256
59 | var d uint128
60 |
61 | for i := 0; i < len(key); i++ {
62 | k <<= 8
63 | k |= uint256(key[i])
64 | }
65 | for i := 0; i < len(data); i++ {
66 | d <<= 8
67 | d |= uint128(data[i])
68 | }
69 |
70 | c := block256(k, d)
71 | var cipher [16]byte
72 | for i := len(cipher) - 1; i >= 0; i-- {
73 | cipher[i] = c & 0xff
74 | c >>= 8
75 | }
76 | return cipher
77 | }
78 |
79 | func block128(key uint128, block uint128) uint128 {
80 | return native("aes_128.circ", key, block)
81 | }
82 |
83 | func block192(key uint192, block uint128) uint128 {
84 | return native("aes_192.circ", key, block)
85 | }
86 |
87 | func block256(key uint256, block uint128) uint128 {
88 | return native("aes_256.circ", key, block)
89 | }
90 |
--------------------------------------------------------------------------------
/pkg/crypto/bloom/bloom.qcl:
--------------------------------------------------------------------------------
1 | package bloom
2 |
3 | func Intersect(left []byte, right []byte) bool {
4 | count := 0
5 | var b byte
6 | for i := 0; i < len(left); i++ {
7 | b = left[i] & right[i]
8 |
9 | if b & 1 == 1 {
10 | count++
11 | }
12 | if b >> 1 & 1 == 1 {
13 | count++
14 | }
15 | if b >> 2 & 1 == 1 {
16 | count++
17 | }
18 | if b >> 3 & 1 == 1 {
19 | count++
20 | }
21 | if b >> 4 & 1 == 1 {
22 | count++
23 | }
24 | if b >> 5 & 1 == 1 {
25 | count++
26 | }
27 | if b >> 6 & 1 == 1 {
28 | count++
29 | }
30 | if b >> 7 & 1 == 1 {
31 | count++
32 | }
33 | }
34 |
35 | result := count > 3
36 | return result
37 | }
--------------------------------------------------------------------------------
/pkg/crypto/cipher/cbc/cbc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package cbc implements the cipher block chaining (CBC) mode of
9 | // operation for block ciphers.
10 | package cbc
11 |
12 | import (
13 | "crypto/aes"
14 | )
15 |
16 | // PadAES pads the data to AES cipher block boundary. The padding is
17 | // filled with byte value describing the padding length. Note that
18 | // data will be always padded. If the original data is already padded,
19 | // the padding will be one full AES block.
20 | func PadAES(data []byte) []byte {
21 | padLen := aes.BlockSize - len(data)%aes.BlockSize
22 | var padded [len(data) + padLen]byte
23 |
24 | for i := 0; i < padLen; i++ {
25 | padded[len(data)+i] = byte(padLen)
26 | }
27 | padded = memcpy(padded, 0, data, 0)
28 |
29 | return padded
30 | }
31 |
32 | // EncryptAES128 encrypts the data in AES-CBC mode. The key specifies
33 | // the AES encryption key and iv is a random initialization
34 | // vector. The data must be padded to AES block size.
35 | //
36 | // // Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key
37 | // // Key : 0x06a9214036b8a15b512e03d534120006
38 | // // IV : 0x3dafba429d9eb430b422da802c9fac41
39 | // // Plaintext : "Single block msg"
40 | // // Ciphertext: 0xe353779c1079aeb82708942dbe77181a
41 | //
42 | // key := []byte{
43 | // 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
44 | // 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06,
45 | // }
46 | // iv := []byte{
47 | // 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
48 | // 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41,
49 | // }
50 | // plain := []byte("Single block msg")
51 | //
52 | // cipher := cbc.EncryptAES128(key, iv, plain)
53 | // => e353779c1079aeb82708942dbe77181a
54 | //
55 | func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte {
56 | var block [aes.BlockSize]byte
57 | block = memcpy(block, 0, iv, 0)
58 |
59 | var plain [aes.BlockSize]byte
60 | var cipher [len(data)]byte
61 |
62 | for i := 0; i < len(data)/aes.BlockSize; i++ {
63 | plain = memcpy(plain, 0, data, i*aes.BlockSize)
64 | for j := 0; j < aes.BlockSize; j++ {
65 | plain[j] ^= block[j]
66 | }
67 | //block = aes.Block128(key, plain)
68 | block = aes.EncryptBlock(key, plain)
69 | cipher = memcpy(cipher, i*aes.BlockSize, block, 0)
70 | }
71 |
72 | return cipher
73 | }
74 |
75 | func DecryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte {
76 | var block [aes.BlockSize]byte
77 |
78 | var cipher [aes.BlockSize]byte
79 | var plain [len(data)]byte
80 |
81 | for i := 0; i < len(data)/aes.BlockSize; i++ {
82 | cipher = memcpy(cipher, 0, data, i*aes.BlockSize)
83 | block = aes.DecryptBlock(key, cipher)
84 | for j := 0; j < aes.BlockSize; j++ {
85 | block[j] ^= iv[j]
86 | }
87 | plain = memcpy(plain, i*aes.BlockSize, block, 0)
88 | iv = memcpy(iv, 0, cipher, 0)
89 | }
90 |
91 | return plain
92 | }
93 |
94 | func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte {
95 | for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ {
96 | dst[dstOfs+i] = src[srcOfs+i]
97 | }
98 | return dst
99 | }
100 |
--------------------------------------------------------------------------------
/pkg/crypto/ed25519/README.md:
--------------------------------------------------------------------------------
1 | * Ed25519
2 |
--------------------------------------------------------------------------------
/pkg/crypto/ed25519/keygen.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // Ed25519 key generation in QCL. This file is derived from Go's
6 | // crypto/ed25519 package. The original copyright notice follows:
7 | //
8 | // Copyright 2016 The Go Authors. All rights reserved.
9 | // Use of this source code is governed by a BSD-style
10 | // license that can be found in the LICENSE file.
11 |
12 | // Package ed25519 implements the Ed25519 signature algorithm.
13 | package ed25519
14 |
15 | import (
16 | "crypto/ed25519/internal/edwards25519"
17 | "crypto/sha512"
18 | )
19 |
20 | // NewKeyFromSeed calculates a private key and a public key from a
21 | // seed. RFC 8032's private keys correspond to seeds in this package.
22 | func NewKeyFromSeed(seed [SeedSize]byte) (PublicKey, PrivateKey) {
23 | digest := sha512.Sum512(seed)
24 | digest[0] &= 248
25 | digest[31] &= 127
26 | digest[31] |= 64
27 |
28 | var A edwards25519.ExtendedGroupElement
29 | var hBytes [32]byte
30 | hBytes = memcpy(hBytes, 0, digest, 0)
31 | edwards25519.GeScalarMultBase(&A, &hBytes)
32 | var publicKeyBytes [32]byte
33 | A.ToBytes(&publicKeyBytes)
34 |
35 | var privateKey [64]byte
36 | privateKey = memcpy(privateKey, 0, seed, 0)
37 | privateKey = memcpy(privateKey, 32, publicKeyBytes, 0)
38 |
39 | return publicKeyBytes, privateKey
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/crypto/ed25519/sign.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // Ed25519 signature computation in QCL. This file is derived from
6 | // Go's crypto/ed25519 package. The original copyright notice follows:
7 | //
8 | // Copyright 2016 The Go Authors. All rights reserved.
9 | // Use of this source code is governed by a BSD-style
10 | // license that can be found in the LICENSE file.
11 |
12 | package ed25519
13 |
14 | import (
15 | "crypto/ed25519/internal/edwards25519"
16 | "crypto/sha512"
17 | )
18 |
19 | const (
20 | // PublicKeySize is the size, in bytes, of public keys as used in
21 | // this package.
22 | PublicKeySize = 32
23 | // PrivateKeySize is the size, in bytes, of private keys as used
24 | // in this package.
25 | PrivateKeySize = 64
26 | // SignatureSize is the size, in bytes, of signatures generated
27 | // and verified by this package.
28 | SignatureSize = 64
29 | // SeedSize is the size, in bytes, of private key seeds. These are
30 | // the private key representations used by RFC 8032.
31 | SeedSize = 32
32 | )
33 |
34 | // PrivateKey defines the Ed25519 private key.
35 | // XXX type PrivateKey [PrivateKeySize]byte
36 | type PrivateKey [64]byte
37 |
38 | // PublicKey defines the Ed25519 public key.
39 | // XXX type PublicKey [PublicKeySize]byte
40 | type PublicKey [32]byte
41 |
42 | // Sign signs the message with privateKey and returns the signature.
43 | func Sign(privateKey PrivateKey, message []byte) []byte {
44 |
45 | digest1 := sha512.Sum512(privateKey[0:32])
46 |
47 | var expandedSecretKey [32]byte
48 | expandedSecretKey = memcpy(expandedSecretKey, 0, digest1, 0)
49 | expandedSecretKey[0] &= 248
50 | expandedSecretKey[31] &= 63
51 | expandedSecretKey[31] |= 64
52 |
53 | buf := make([]byte, 32+len(message))
54 | buf = memcpy(buf, 0, digest1, 32)
55 | buf = memcpy(buf, 32, message, 0)
56 | messageDigest := sha512.Sum512(buf)
57 |
58 | var messageDigestReduced [32]byte
59 | edwards25519.ScReduce(&messageDigestReduced, messageDigest)
60 | var R edwards25519.ExtendedGroupElement
61 | edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
62 |
63 | var encodedR [32]byte
64 | R.ToBytes(&encodedR)
65 |
66 | buf2 := make([]byte, 64+len(message))
67 | buf2 = memcpy(buf2, 0, encodedR, 0)
68 | buf2 = memcpy(buf2, 32, privateKey, 32)
69 | buf2 = memcpy(buf2, 64, message, 0)
70 | hramDigest := sha512.Sum512(buf2)
71 |
72 | var hramDigestReduced [32]byte
73 | edwards25519.ScReduce(&hramDigestReduced, hramDigest)
74 |
75 | var s [32]byte
76 | edwards25519.ScMulAdd(&s, hramDigestReduced, expandedSecretKey,
77 | messageDigestReduced)
78 |
79 | var signature [SignatureSize]byte
80 | signature = memcpy(signature, 0, encodedR, 0)
81 | signature = memcpy(signature, 32, s, 0)
82 |
83 | return signature
84 | }
85 |
86 | func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte {
87 | for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ {
88 | dst[dstOfs+i] = src[srcOfs+i]
89 | }
90 | return dst
91 | }
92 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/constants.qcl:
--------------------------------------------------------------------------------
1 | package ed448
2 |
3 | var (
4 | // genX is the x-coordinate of the generator of Goldilocks curve.
5 | genX = Elt{
6 | 0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26,
7 | 0x8e, 0x93, 0x00, 0x8b, 0xe1, 0x80, 0x3b, 0x43,
8 | 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12,
9 | 0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea,
10 | 0x67, 0x17, 0x0f, 0x47, 0x70, 0x65, 0x14, 0x9e,
11 | 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
12 | 0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f,
13 | }
14 | // genY is the y-coordinate of the generator of Goldilocks curve.
15 | genY = Elt{
16 | 0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98,
17 | 0xad, 0xc8, 0xd7, 0x4e, 0x2c, 0x13, 0xbd, 0xfd,
18 | 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
19 | 0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87,
20 | 0x40, 0x98, 0xa3, 0x6c, 0x73, 0x73, 0xea, 0x4b,
21 | 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
22 | 0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69,
23 | }
24 | // paramD is -39081 in
25 | paramD = Elt{
26 | 0x56, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
27 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
28 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29 | 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
30 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 | }
34 | // order is 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d,
35 | // which is the number of points in the prime subgroup.
36 | order = Scalar{
37 | 0xf3, 0x44, 0x58, 0xab, 0x92, 0xc2, 0x78, 0x23,
38 | 0x55, 0x8f, 0xc5, 0x8d, 0x72, 0xc2, 0x6c, 0x21,
39 | 0x90, 0x36, 0xd6, 0xae, 0x49, 0xdb, 0x4e, 0xc4,
40 | 0xe9, 0x23, 0xca, 0x7c, 0xff, 0xff, 0xff, 0xff,
41 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
44 | }
45 | // residue448 is 2^448 mod order.
46 | residue448 = [4]uint64{
47 | 0x721cf5b5529eec34, 0x7a4cf635c8e9c2ab, 0xeec492d944a725bf, 0x20cd77058,
48 | }
49 | // invFour is 1/4 mod order.
50 | invFour = Scalar{
51 | 0x3d, 0x11, 0xd6, 0xaa, 0xa4, 0x30, 0xde, 0x48,
52 | 0xd5, 0x63, 0x71, 0xa3, 0x9c, 0x30, 0x5b, 0x08,
53 | 0xa4, 0x8d, 0xb5, 0x6b, 0xd2, 0xb6, 0x13, 0x71,
54 | 0xfa, 0x88, 0x32, 0xdf, 0xff, 0xff, 0xff, 0xff,
55 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
58 | }
59 | // paramDTwist is -39082 in The D parameter of the twist curve.
60 | paramDTwist = Elt{
61 | 0x55, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
62 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64 | 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff,
65 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68 | }
69 | )
70 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/curve.qcl:
--------------------------------------------------------------------------------
1 | // Package goldilocks provides elliptic curve operations over the goldilocks curve.
2 | package ed448
3 |
4 | // Curve is the Goldilocks curve x^2+y^2=z^2-39081x^2y^2.
5 | type Curve struct{}
6 |
7 | // Identity returns the identity point.
8 | func (Curve) Identity() *Point {
9 | return &Point{
10 | y: One(),
11 | z: One(),
12 | }
13 | }
14 |
15 | // IsOnCurve returns true if the point lies on the curve.
16 | func (Curve) IsOnCurve(P *Point) bool {
17 | x2, y2, t, t2, z2 := &Elt{}, &Elt{}, &Elt{}, &Elt{}, &Elt{}
18 | rhs, lhs := &Elt{}, &Elt{}
19 | Mul(t, &P.ta, &P.tb) // t = ta*tb
20 | Sqr(x2, &P.x) // x^2
21 | Sqr(y2, &P.y) // y^2
22 | Sqr(z2, &P.z) // z^2
23 | Sqr(t2, t) // t^2
24 | Add(lhs, x2, y2) // x^2 + y^2
25 | Mul(rhs, t2, ¶mD) // dt^2
26 | Add(rhs, rhs, z2) // z^2 + dt^2
27 | Sub(lhs, lhs, rhs) // x^2 + y^2 - (z^2 + dt^2)
28 | eq0 := IsZero(lhs)
29 |
30 | Mul(lhs, &P.x, &P.y) // xy
31 | Mul(rhs, t, &P.z) // tz
32 | Sub(lhs, lhs, rhs) // xy - tz
33 | eq1 := IsZero(lhs)
34 | return eq0 && eq1
35 | }
36 |
37 | // Generator returns the generator point.
38 | func (Curve) Generator() *Point {
39 | return &Point{
40 | x: genX,
41 | y: genY,
42 | z: One(),
43 | ta: genX,
44 | tb: genY,
45 | }
46 | }
47 |
48 | // Order returns the number of points in the prime subgroup.
49 | func (Curve) Order() Scalar { return order }
50 |
51 | // Double returns 2P.
52 | func (Curve) Double(P *Point) *Point { R := *P; R.Double(); return &R }
53 |
54 | // Add returns P+Q.
55 | func (Curve) Add(P, Q *Point) *Point { R := *P; R.Add(Q); return &R }
56 |
57 | // ScalarMult returns kP. This function runs in constant time.
58 | func (e Curve) ScalarMult(k *Scalar, P *Point) *Point {
59 | k4 := &Scalar{}
60 | k4.divBy4(k)
61 | return e.pull(twistCurve{}.ScalarMult(k4, e.push(P)))
62 | }
63 |
64 | // ScalarBaseMult returns kG where G is the generator point. This function runs in constant time.
65 | func (e Curve) ScalarBaseMult(k *Scalar) *Point {
66 | k4 := &Scalar{}
67 | k4.divBy4(k)
68 | return e.pull(twistCurve{}.ScalarBaseMult(k4))
69 | }
70 |
71 | // CombinedMult returns mG+nP, where G is the generator point. This function is non-constant time.
72 | func (e Curve) CombinedMult(m, n *Scalar, P *Point) *Point {
73 | m4 := &Scalar{}
74 | n4 := &Scalar{}
75 | m4.divBy4(m)
76 | n4.divBy4(n)
77 | return e.pull(twistCurve{}.CombinedMult(m4, n4, twistCurve{}.pull(P)))
78 | }
79 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/fp_noasm.qcl:
--------------------------------------------------------------------------------
1 | //go:build !amd64 || purego
2 | // +build !amd64 purego
3 |
4 | package ed448
5 |
6 | func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) }
7 | func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) }
8 | func add(z, x, y *Elt) { addGeneric(z, x, y) }
9 | func sub(z, x, y *Elt) { subGeneric(z, x, y) }
10 | func addsub(x, y *Elt) { addsubGeneric(x, y) }
11 | func mul(z, x, y *Elt) { mulGeneric(z, x, y) }
12 | func sqr(z, x *Elt) { sqrGeneric(z, x) }
13 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/isogeny.qcl:
--------------------------------------------------------------------------------
1 | package ed448
2 |
3 | func (Curve) pull(P *twistPoint) *Point { return twistCurve{}.push(P) }
4 | func (twistCurve) pull(P *Point) *twistPoint { return Curve{}.push(P) }
5 |
6 | // push sends a point on the Goldilocks curve to a point on the twist curve.
7 | func (Curve) push(P *Point) *twistPoint {
8 | Q := &twistPoint{}
9 | Px, Py, Pz := &P.x, &P.y, &P.z
10 | a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb
11 | Add(e, Px, Py) // x+y
12 | Sqr(a, Px) // A = x^2
13 | Sqr(b, Py) // B = y^2
14 | Sqr(c, Pz) // z^2
15 | Add(c, c, c) // C = 2*z^2
16 | *d = *a // D = A
17 | Sqr(e, e) // (x+y)^2
18 | Sub(e, e, a) // (x+y)^2-A
19 | Sub(e, e, b) // E = (x+y)^2-A-B
20 | Add(h, b, d) // H = B+D
21 | Sub(g, b, d) // G = B-D
22 | Sub(f, c, h) // F = C-H
23 | Mul(&Q.z, f, g) // Z = F * G
24 | Mul(&Q.x, e, f) // X = E * F
25 | Mul(&Q.y, g, h) // Y = G * H, // T = E * H
26 | return Q
27 | }
28 |
29 | // push sends a point on the twist curve to a point on the Goldilocks curve.
30 | func (twistCurve) push(P *twistPoint) *Point {
31 | Q := &Point{}
32 | Px, Py, Pz := &P.x, &P.y, &P.z
33 | a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb
34 | Add(e, Px, Py) // x+y
35 | Sqr(a, Px) // A = x^2
36 | Sqr(b, Py) // B = y^2
37 | Sqr(c, Pz) // z^2
38 | Add(c, c, c) // C = 2*z^2
39 | Neg(d, a) // D = -A
40 | Sqr(e, e) // (x+y)^2
41 | Sub(e, e, a) // (x+y)^2-A
42 | Sub(e, e, b) // E = (x+y)^2-A-B
43 | Add(h, b, d) // H = B+D
44 | Sub(g, b, d) // G = B-D
45 | Sub(f, c, h) // F = C-H
46 | Mul(&Q.z, f, g) // Z = F * G
47 | Mul(&Q.x, e, f) // X = E * F
48 | Mul(&Q.y, g, h) // Y = G * H, // T = E * H
49 | return Q
50 | }
51 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/power.qcl:
--------------------------------------------------------------------------------
1 | package ed448
2 |
3 | import "fmt"
4 |
5 | // Power is a valid exponent produced by the MLSBSet encoding algorithm.
6 | type Power struct {
7 | set Encoder // parameters of code.
8 | s []int32 // set of signs.
9 | b []int32 // set of digits.
10 | c int // carry is {0,1}.
11 | }
12 |
13 | // Exp is calculates x^k, where x is a predetermined element of a group G.
14 | func (p *Power) Exp(G Group) EltG {
15 | a, b := G.Identity(), G.NewEltP()
16 | for e := int(p.set.p.E - 1); e >= 0; e-- {
17 | G.Sqr(a)
18 | for v := uint(0); v < p.set.p.V; v++ {
19 | sgnElt, idElt := p.Digit(v, uint(e))
20 | G.Lookup(b, v, sgnElt, idElt)
21 | G.Mul(a, b)
22 | }
23 | }
24 | if p.set.IsExtended() && p.c == 1 {
25 | G.Mul(a, G.ExtendedEltP())
26 | }
27 | return a
28 | }
29 |
30 | // Digit returns the (v,e)-th digit and its sign.
31 | func (p *Power) Digit(v, e uint) (sgn, dig int32) {
32 | sgn = p.bit(0, v, e)
33 | dig = 0
34 | for i := p.set.p.W - 1; i > 0; i-- {
35 | dig = 2*dig + p.bit(i, v, e)
36 | }
37 | mask := dig >> 31
38 | dig = (dig + mask) ^ mask
39 | return sgn, dig
40 | }
41 |
42 | // bit returns the (w,v,e)-th bit of the code.
43 | func (p *Power) bit(w, v, e uint) int32 {
44 | if !(w < p.set.p.W &&
45 | v < p.set.p.V &&
46 | e < p.set.p.E) {
47 | panic(fmt.Errorf("indexes outside (%v,%v,%v)", w, v, e))
48 | }
49 | if w == 0 {
50 | return p.s[p.set.p.E*v+e]
51 | }
52 | return p.b[p.set.p.D*(w-1)+p.set.p.E*v+e]
53 | }
54 |
55 | func (p *Power) String() string {
56 | dig := ""
57 | for j := uint(0); j < p.set.p.V; j++ {
58 | for i := uint(0); i < p.set.p.E; i++ {
59 | s, d := p.Digit(j, i)
60 | dig += fmt.Sprintf("(%2v,%2v) = %+2v %+2v\n", j, i, s, d)
61 | }
62 | }
63 | return fmt.Sprintf("len: %v\ncarry: %v\ndigits:\n%v", len(p.b)+len(p.s), p.c, dig)
64 | }
65 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/twist.qcl:
--------------------------------------------------------------------------------
1 | package ed448
2 |
3 | import (
4 | "crypto/subtle"
5 | "math/bits"
6 | )
7 |
8 | // twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogeneous to Goldilocks.
9 | type twistCurve struct{}
10 |
11 | // Identity returns the identity point.
12 | func (twistCurve) Identity() *twistPoint {
13 | return &twistPoint{
14 | y: One(),
15 | z: One(),
16 | }
17 | }
18 |
19 | // subYDiv16 update x = (x - y) / 16.
20 | func subYDiv16(x *scalar64, y int64) {
21 | s := uint64(y >> 63)
22 | x0, b0 := bits.Sub64((*x)[0], uint64(y), 0)
23 | x1, b1 := bits.Sub64((*x)[1], s, b0)
24 | x2, b2 := bits.Sub64((*x)[2], s, b1)
25 | x3, b3 := bits.Sub64((*x)[3], s, b2)
26 | x4, b4 := bits.Sub64((*x)[4], s, b3)
27 | x5, b5 := bits.Sub64((*x)[5], s, b4)
28 | x6, _ := bits.Sub64((*x)[6], s, b5)
29 | x[0] = (x0 >> 4) | (x1 << 60)
30 | x[1] = (x1 >> 4) | (x2 << 60)
31 | x[2] = (x2 >> 4) | (x3 << 60)
32 | x[3] = (x3 >> 4) | (x4 << 60)
33 | x[4] = (x4 >> 4) | (x5 << 60)
34 | x[5] = (x5 >> 4) | (x6 << 60)
35 | x[6] = (x6 >> 4)
36 | }
37 |
38 | func recodeScalar(d *[113]int8, k *Scalar) {
39 | var k64 scalar64
40 | k64.fromScalar(k)
41 | for i := 0; i < 112; i++ {
42 | d[i] = int8((k64[0] & 0x1f) - 16)
43 | subYDiv16(&k64, int64(d[i]))
44 | }
45 | d[112] = int8(k64[0])
46 | }
47 |
48 | // ScalarMult returns kP.
49 | func (e twistCurve) ScalarMult(k *Scalar, P *twistPoint) *twistPoint {
50 | var TabP [8]preTwistPointProy
51 | var S preTwistPointProy
52 | var d [113]int8
53 |
54 | var isZero int
55 | if k.IsZero() {
56 | isZero = 1
57 | }
58 | subtle.ConstantTimeCopy(isZero, k[:], order[:])
59 |
60 | minusK := *k
61 | isEven := 1 - int(k[0]&0x1)
62 | minusK.Neg()
63 | subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
64 | recodeScalar(&d, k)
65 |
66 | P.oddMultiples(TabP[:])
67 | Q := e.Identity()
68 | for i := 112; i >= 0; i-- {
69 | Q.Double()
70 | Q.Double()
71 | Q.Double()
72 | Q.Double()
73 | mask := d[i] >> 7
74 | absDi := (d[i] + mask) ^ mask
75 | inx := int32((absDi - 1) >> 1)
76 | sig := int((d[i] >> 7) & 0x1)
77 | for j := range TabP {
78 | S.cmov(&TabP[j], uint(subtle.ConstantTimeEq(inx, int32(j))))
79 | }
80 | S.cneg(sig)
81 | Q.mixAdd(&S)
82 | }
83 | Q.cneg(uint(isEven))
84 | return Q
85 | }
86 |
87 | const (
88 | omegaFix = 7
89 | omegaVar = 5
90 | )
91 |
92 | // CombinedMult returns mG+nP.
93 | func (e twistCurve) CombinedMult(m, n *Scalar, P *twistPoint) *twistPoint {
94 | nafFix := OmegaNAF(BytesLe2BigInt(m[:]), omegaFix)
95 | nafVar := OmegaNAF(BytesLe2BigInt(n[:]), omegaVar)
96 |
97 | if len(nafFix) > len(nafVar) {
98 | nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...)
99 | } else if len(nafFix) < len(nafVar) {
100 | nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...)
101 | }
102 |
103 | var TabQ [1 << (omegaVar - 2)]preTwistPointProy
104 | P.oddMultiples(TabQ[:])
105 | Q := e.Identity()
106 | for i := len(nafFix) - 1; i >= 0; i-- {
107 | Q.Double()
108 | // Generator point
109 | if nafFix[i] != 0 {
110 | idxM := absolute(nafFix[i]) >> 1
111 | R := tabVerif[idxM]
112 | if nafFix[i] < 0 {
113 | R.neg()
114 | }
115 | Q.mixAddZ1(&R)
116 | }
117 | // Variable input point
118 | if nafVar[i] != 0 {
119 | idxN := absolute(nafVar[i]) >> 1
120 | S := TabQ[idxN]
121 | if nafVar[i] < 0 {
122 | S.neg()
123 | }
124 | Q.mixAdd(&S)
125 | }
126 | }
127 | return Q
128 | }
129 |
130 | // absolute returns always a positive value.
131 | func absolute(x int32) int32 {
132 | mask := x >> 31
133 | return (x + mask) ^ mask
134 | }
135 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/twist_basemult.qcl:
--------------------------------------------------------------------------------
1 | package ed448
2 |
3 | import (
4 | "crypto/subtle"
5 | )
6 |
7 | const (
8 | // MLSBRecoding parameters
9 | fxT = 448
10 | fxV = 2
11 | fxW = 3
12 | fx2w1 = 1 << (uint(fxW) - 1)
13 | )
14 |
15 | // ScalarBaseMult returns kG where G is the generator point.
16 | func (e twistCurve) ScalarBaseMult(k *Scalar) *twistPoint {
17 | m, err := New(fxT, fxV, fxW)
18 | if err != nil {
19 | panic(err)
20 | }
21 | if m.IsExtended() {
22 | panic("not extended")
23 | }
24 |
25 | var isZero int
26 | if k.IsZero() {
27 | isZero = 1
28 | }
29 | subtle.ConstantTimeCopy(isZero, k[:], order[:])
30 |
31 | minusK := *k
32 | isEven := 1 - int(k[0]&0x1)
33 | minusK.Neg()
34 | subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
35 | c, err := m.Encode(k[:])
36 | if err != nil {
37 | panic(err)
38 | }
39 |
40 | gP := c.Exp(groupMLSB{})
41 | P := gP.(*twistPoint)
42 | P.cneg(uint(isEven))
43 | return P
44 | }
45 |
46 | type groupMLSB struct{}
47 |
48 | func (e groupMLSB) ExtendedEltP() EltP { return nil }
49 | func (e groupMLSB) Sqr(x EltG) { x.(*twistPoint).Double() }
50 | func (e groupMLSB) Mul(x EltG, y EltP) { x.(*twistPoint).mixAddZ1(y.(*preTwistPointAffine)) }
51 | func (e groupMLSB) Identity() EltG { return twistCurve{}.Identity() }
52 | func (e groupMLSB) NewEltP() EltP { return &preTwistPointAffine{} }
53 | func (e groupMLSB) Lookup(a EltP, v uint, s, u int32) {
54 | Tabj := &tabFixMult[v]
55 | P := a.(*preTwistPointAffine)
56 | for k := range Tabj {
57 | P.cmov(&Tabj[k], uint(subtle.ConstantTimeEq(int32(k), u)))
58 | }
59 | P.cneg(int(s >> 31))
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/crypto/ed448/wnaf.qcl:
--------------------------------------------------------------------------------
1 | // Package math provides some utility functions for big integers.
2 | package ed448
3 |
4 | import "math/big"
5 |
6 | // SignedDigit obtains the signed-digit recoding of n and returns a list L of
7 | // digits such that n = sum( L[i]*2^(i*(w-1)) ), and each L[i] is an odd number
8 | // in the set {±1, ±3, ..., ±2^(w-1)-1}. The third parameter ensures that the
9 | // output has ceil(l/(w-1)) digits.
10 | //
11 | // Restrictions:
12 | // - n is odd and n > 0.
13 | // - 1 < w < 32.
14 | // - l >= bit length of n.
15 | //
16 | // References:
17 | // - Alg.6 in "Exponent Recoding and Regular Exponentiation Algorithms"
18 | // by Joye-Tunstall. http://doi.org/10.1007/978-3-642-02384-2_21
19 | // - Alg.6 in "Selecting Elliptic Curves for Cryptography: An Efficiency and
20 | // Security Analysis" by Bos et al. http://doi.org/10.1007/s13389-015-0097-y
21 | func SignedDigit(n *big.Int, w, l uint) []int32 {
22 | if n.Sign() <= 0 || n.Bit(0) == 0 {
23 | panic("n must be non-zero, odd, and positive")
24 | }
25 | if w <= 1 || w >= 32 {
26 | panic("Verify that 1 < w < 32")
27 | }
28 | if uint(n.BitLen()) > l {
29 | panic("n is too big to fit in l digits")
30 | }
31 | lenN := (l + (w - 1) - 1) / (w - 1) // ceil(l/(w-1))
32 | L := make([]int32, lenN+1)
33 | var k, v big.Int
34 | k.Set(n)
35 |
36 | var i uint
37 | for i = 0; i < lenN; i++ {
38 | words := k.Bits()
39 | value := int32(words[0] & ((1 << w) - 1))
40 | value -= int32(1) << (w - 1)
41 | L[i] = value
42 | v.SetInt64(int64(value))
43 | k.Sub(&k, &v)
44 | k.Rsh(&k, w-1)
45 | }
46 | L[i] = int32(k.Int64())
47 | return L
48 | }
49 |
50 | // OmegaNAF obtains the window-w Non-Adjacent Form of a positive number n and
51 | // 1 < w < 32. The returned slice L holds n = sum( L[i]*2^i ).
52 | //
53 | // Reference:
54 | // - Alg.9 "Efficient arithmetic on Koblitz curves" by Solinas.
55 | // http://doi.org/10.1023/A:1008306223194
56 | func OmegaNAF(n *big.Int, w uint) (L []int32) {
57 | if n.Sign() < 0 {
58 | panic("n must be positive")
59 | }
60 | if w <= 1 || w >= 32 {
61 | panic("Verify that 1 < w < 32")
62 | }
63 |
64 | L = make([]int32, n.BitLen()+1)
65 | var k, v big.Int
66 | k.Set(n)
67 |
68 | i := 0
69 | for ; k.Sign() > 0; i++ {
70 | value := int32(0)
71 | if k.Bit(0) == 1 {
72 | words := k.Bits()
73 | value = int32(words[0] & ((1 << w) - 1))
74 | if value >= (int32(1) << (w - 1)) {
75 | value -= int32(1) << w
76 | }
77 | v.SetInt64(int64(value))
78 | k.Sub(&k, &v)
79 | }
80 | L[i] = value
81 | k.Rsh(&k, 1)
82 | }
83 | return L[:i]
84 | }
85 |
--------------------------------------------------------------------------------
/pkg/crypto/hmac/doc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package hmac implements Keyed-Hash Message Authentication Code
9 | // (HMAC) functions. All functions take the data that is authenticated and
10 | // an authentication key.
11 | //
12 | // signature := hmac.SumSHA256([]byte("message"), []byte("abc"))
13 | // => 859cc656e12c0ecd0afdd7e3d034c3ee81609fcac1b454c231211c7ac69895e8
14 | package hmac
15 |
--------------------------------------------------------------------------------
/pkg/crypto/hmac/sha256.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package hmac
9 |
10 | import (
11 | "crypto/sha256"
12 | )
13 |
14 | // SumSHA256 computes the HMAC-SHA256 signature for the data using the
15 | // key.
16 | func SumSHA256(data, key []byte) [sha256.Size]byte {
17 | if len(key) > sha256.BlockSize {
18 | key = sha256.Sum256(key[:])
19 | }
20 |
21 | var ipad [sha256.BlockSize]byte
22 | var opad [sha256.BlockSize]byte
23 |
24 | ipad = memcpy(ipad, 0, key, 0)
25 | opad = memcpy(opad, 0, key, 0)
26 |
27 | for i := 0; i < len(ipad); i++ {
28 | ipad[i] ^= 0x36
29 | }
30 | for i := 0; i < len(opad); i++ {
31 | opad[i] ^= 0x5c
32 | }
33 |
34 | var idata [len(ipad) + len(data)]byte
35 | idata = memcpy(idata, 0, ipad, 0)
36 | idata = memcpy(idata, len(ipad), data, 0)
37 |
38 | idigest := sha256.Sum256(idata[:])
39 |
40 | var odata [len(opad) + len(idigest)]byte
41 | odata = memcpy(odata, 0, opad, 0)
42 | odata = memcpy(odata, len(opad), idigest, 0)
43 |
44 | return sha256.Sum256(odata[:])
45 | }
46 |
47 | func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte {
48 | for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ {
49 | dst[dstOfs+i] = src[srcOfs+i]
50 | }
51 | return dst
52 | }
53 |
--------------------------------------------------------------------------------
/pkg/crypto/hmac/sha512.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package hmac
9 |
10 | import (
11 | "crypto/sha512"
12 | )
13 |
14 | // SumSHA512 computes the HMAC-SHA512 signature for the data using the
15 | // key.
16 | func SumSHA512(data, key []byte) [sha512.Size]byte {
17 | if len(key) > sha512.BlockSize {
18 | key = sha512.Sum512(key[:])
19 | }
20 |
21 | var ipad [sha512.BlockSize]byte
22 | var opad [sha512.BlockSize]byte
23 |
24 | ipad = memcpy(ipad, 0, key, 0)
25 | opad = memcpy(opad, 0, key, 0)
26 |
27 | for i := 0; i < len(ipad); i++ {
28 | ipad[i] ^= 0x36
29 | }
30 | for i := 0; i < len(opad); i++ {
31 | opad[i] ^= 0x5c
32 | }
33 |
34 | var idata [len(ipad) + len(data)]byte
35 | idata = memcpy(idata, 0, ipad, 0)
36 | idata = memcpy(idata, len(ipad), data, 0)
37 |
38 | idigest := sha512.Sum512(idata[:])
39 |
40 | var odata [len(opad) + len(idigest)]byte
41 | odata = memcpy(odata, 0, opad, 0)
42 | odata = memcpy(odata, len(opad), idigest, 0)
43 |
44 | return sha512.Sum512(odata[:])
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/crypto/rsa/rsa.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package rsa implements RSA encrypt and decrypt operations. The
9 | // practical key sizes are <= 512 bits i.e. this must not be used in
10 | // any real life applications.
11 | package rsa
12 |
13 | import (
14 | "math"
15 | )
16 |
17 | const (
18 | // E65537 is the public RSA exponent 2^16+1.
19 | E65537 = 0x10001
20 | )
21 |
22 | // Encrypt encrypts the message with the public key {e, n}.
23 | // cipher = msg**e mod n
24 | func Encrypt(msg, e, n uint) uint {
25 | return math.Exp(msg, e, n)
26 | }
27 |
28 | // Decrypt decrypts the cipher text with the private key {d, n}.
29 | // message = cipher**d mod n
30 | func Decrypt(cipher, d, n uint) uint {
31 | return math.Exp(cipher, d, n)
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/crypto/sha256/sum.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package sha256 implements the he SHA-224 and SHA-256 cryptographic
9 | // hash functions.
10 | package sha256
11 |
12 | const (
13 | // The size of a SHA256 checksum in bytes.
14 | Size = 32
15 |
16 | // The blocksize of SHA256 and SHA224 in bytes.
17 | BlockSize = 64
18 |
19 | init = 0x6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19
20 | )
21 |
22 | // Sum256 returns the SHA256 checksum of the data.
23 | func Sum256(data []byte) [Size]byte {
24 | var state uint256 = init
25 | var block uint512
26 | var hash [Size]byte
27 |
28 | var pad [BlockSize]byte
29 | pad[0] = 0x80
30 |
31 | for i := 0; i < len(data); i++ {
32 | block <<= 8
33 | block = block | uint512(data[i])
34 |
35 | if (i+1)%BlockSize == 0 {
36 | state = Block(block, state)
37 | block = uint512(0)
38 | }
39 | }
40 | if len(data)%BlockSize < 56 {
41 | for i := len(data) % BlockSize; i < 56; i++ {
42 | block <<= 8
43 | block |= uint512(pad[i-len(data)%BlockSize])
44 | }
45 | } else {
46 | for i := len(data) % BlockSize; i < BlockSize; i++ {
47 | block <<= 8
48 | block |= uint512(pad[i-len(data)%BlockSize])
49 | }
50 | state = Block(block, state)
51 | block = uint512(0)
52 | }
53 | // Length in bits.
54 | block <<= 64
55 | block |= uint512(len(data) << 3)
56 |
57 | state = Block(block, state)
58 |
59 | for i := 0; i < Size; i++ {
60 | hash[Size-i-1] = byte(state & 0xff)
61 | state >>= 8
62 | }
63 | return hash
64 | }
65 |
66 | // Block adds a new SHA-256 block to the state.
67 | func Block(block uint512, state uint256) uint256 {
68 | return native("sha256.circ", block, state)
69 | }
70 |
--------------------------------------------------------------------------------
/pkg/crypto/sha512/sha512.qclc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QuilibriumNetwork/bedlam/80c689d8e0699b5f5a71dde4caac54bcfa506751/pkg/crypto/sha512/sha512.qclc
--------------------------------------------------------------------------------
/pkg/crypto/sha512/sum.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and
9 | // SHA-512/256 cryptographic hash functions.
10 | package sha512
11 |
12 | const (
13 | // The size of a SHA512 checksum in bytes.
14 | Size = 64
15 |
16 | // BlockSize is the block size, in bytes, of the SHA-512/224,
17 | // SHA-512/256, SHA-384 and SHA-512 hash functions.
18 | BlockSize = 128
19 |
20 | init = 0x6a09e667f3bcc908bb67ae8584caa73b3c6ef372fe94f82ba54ff53a5f1d36f1510e527fade682d19b05688c2b3e6c1f1f83d9abfb41bd6b5be0cd19137e2179
21 | )
22 |
23 | // Sum512 returns the SHA512 checksum of the data.
24 | func Sum512(data []byte) [Size]byte {
25 | var state uint512 = init
26 | var block uint1024
27 | var hash [Size]byte
28 |
29 | var pad [BlockSize]byte
30 | pad[0] = 0x80
31 |
32 | for i := 0; i < len(data); i++ {
33 | block <<= 8
34 | block = block | uint1024(data[i])
35 |
36 | if (i+1)%BlockSize == 0 {
37 | state = Block(block, state)
38 | block = uint1024(0)
39 | }
40 | }
41 | if len(data)%BlockSize < 112 {
42 | for i := len(data) % BlockSize; i < 112; i++ {
43 | block <<= 8
44 | block |= uint1024(pad[i-len(data)%BlockSize])
45 | }
46 | } else {
47 | for i := len(data) % BlockSize; i < BlockSize; i++ {
48 | block <<= 8
49 | block |= uint1024(pad[i-len(data)%BlockSize])
50 | }
51 | state = Block(block, state)
52 | block = uint1024(0)
53 | }
54 | // Length in bits.
55 | block <<= 128
56 | block |= uint1024(len(data) << 3)
57 |
58 | state = Block(block, state)
59 |
60 | for i := 0; i < Size; i++ {
61 | hash[Size-i-1] = byte(state & 0xff)
62 | state >>= 8
63 | }
64 | return hash
65 | }
66 |
67 | // Block adds a new SHA-512 block to the state.
68 | func Block(block uint1024, state uint512) uint512 {
69 | return native("sha512.qclc", block, state)
70 | }
71 |
--------------------------------------------------------------------------------
/pkg/crypto/subtle/funcs.qcl:
--------------------------------------------------------------------------------
1 | // Copyright 2009 The Go Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style
3 | // license that can be found in the LICENSE file.
4 |
5 | // Package subtle implements functions that are often useful in cryptographic
6 | // code but require careful thought to use correctly.
7 | package subtle
8 |
9 | // ConstantTimeCompare returns 1 if the two slices, x and y, have equal contents
10 | // and 0 otherwise. The time taken is a function of the length of the slices and
11 | // is independent of the contents. If the lengths of x and y do not match it
12 | // returns 0 immediately.
13 | func ConstantTimeCompare(x, y []byte) int {
14 | if len(x) != len(y) {
15 | return 0
16 | }
17 |
18 | var v byte
19 |
20 | for i := 0; i < len(x); i++ {
21 | v |= x[i] ^ y[i]
22 | }
23 |
24 | return ConstantTimeByteEq(v, 0)
25 | }
26 |
27 | // ConstantTimeSelect returns x if v == 1 and y if v == 0.
28 | // Its behavior is undefined if v takes any other value.
29 | func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
30 |
31 | // ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
32 | func ConstantTimeByteEq(x, y uint8) int {
33 | return int((uint32(x^y) - 1) >> 31)
34 | }
35 |
36 | // ConstantTimeEq returns 1 if x == y and 0 otherwise.
37 | func ConstantTimeEq(x, y int32) int {
38 | return int((uint64(uint32(x^y)) - 1) >> 63)
39 | }
40 |
41 | // ConstantTimeCopy copies the contents of y into x (a slice of equal length)
42 | // if v == 1. If v == 0, x is left unchanged. Its behavior is undefined if v
43 | // takes any other value.
44 | func ConstantTimeCopy(v int, x, y []byte) {
45 | if len(x) != len(y) {
46 | panic("subtle: slices have different lengths")
47 | }
48 |
49 | xmask := byte(v - 1)
50 | ymask := byte(^(v - 1))
51 | for i := 0; i < len(x); i++ {
52 | x[i] = x[i]&xmask | y[i]&ymask
53 | }
54 | }
55 |
56 | // ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
57 | // Its behavior is undefined if x or y are negative or > 2**31 - 1.
58 | func ConstantTimeLessOrEq(x, y int) int {
59 | x32 := int32(x)
60 | y32 := int32(y)
61 | return int(((x32 - y32 - 1) >> 31) & 1)
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/embedded.go:
--------------------------------------------------------------------------------
1 | package pkg
2 |
3 | import "embed"
4 |
5 | //go:embed bits/*
6 | //go:embed bytes/*
7 | //go:embed crypto/*
8 | //go:embed encoding/*
9 | //go:embed math/*
10 | //go:embed sort/*
11 | //go:embed builtin.qcl
12 | var PkgFS embed.FS
13 |
--------------------------------------------------------------------------------
/pkg/encoding/binary/bigendian.qcl:
--------------------------------------------------------------------------------
1 | package binary
2 |
3 | func BigEndianUint16(b []byte) uint16 {
4 | _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
5 | return uint16(b[1]) | uint16(b[0])<<8
6 | }
7 |
8 | func BigEndianPutUint16(b []byte, v uint16) {
9 | _ = b[1] // early bounds check to guarantee safety of writes below
10 | b[0] = byte(v >> 8)
11 | b[1] = byte(v)
12 | }
13 |
14 | func BigEndianAppendUint16(b []byte, v uint16) []byte {
15 | return append(b, byte(v>>8), byte(v))
16 | }
17 |
18 | func BigEndianUint32(b []byte) uint32 {
19 | _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
20 | return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
21 | }
22 |
23 | func BigEndianPutUint32(b []byte, v uint32) {
24 | _ = b[3] // early bounds check to guarantee safety of writes below
25 | b[0] = byte(v >> 24)
26 | b[1] = byte(v >> 16)
27 | b[2] = byte(v >> 8)
28 | b[3] = byte(v)
29 | }
30 |
31 | func BigEndianAppendUint32(b []byte, v uint32) []byte {
32 | return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
33 | }
34 |
35 | func BigEndianUint64(b []byte) uint64 {
36 | _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
37 | return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
38 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
39 | }
40 |
41 | func BigEndianPutUint64(b []byte, v uint64) {
42 | _ = b[7] // early bounds check to guarantee safety of writes below
43 | b[0] = byte(v >> 56)
44 | b[1] = byte(v >> 48)
45 | b[2] = byte(v >> 40)
46 | b[3] = byte(v >> 32)
47 | b[4] = byte(v >> 24)
48 | b[5] = byte(v >> 16)
49 | b[6] = byte(v >> 8)
50 | b[7] = byte(v)
51 | }
52 |
53 | func BigEndianAppendUint64(b []byte, v uint64) []byte {
54 | return append(b, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
55 | }
--------------------------------------------------------------------------------
/pkg/encoding/binary/doc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package binary implements functions for processing binary data.
9 | package binary
10 |
--------------------------------------------------------------------------------
/pkg/encoding/binary/getput.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021-2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package binary
9 |
10 | // GetUint gets a MSB-encoded unsigned integer from the argument
11 | // buffer. The size of the result number is determined by the length
12 | // of the input buffer.
13 | func GetUint(d []byte) uint {
14 | resultType := make(uint, len(d)*8)
15 |
16 | var result resultType
17 | for i := 0; i < len(d); i++ {
18 | result <<= 8
19 | result |= resultType(d[i])
20 | }
21 | return result
22 | }
23 |
24 | // PutUint puts the unsigned integer v to the buffer d starting from
25 | // the offset offset in MSB-order. The number of bytes encoded is
26 | // determined by the size of the input value v.
27 | func PutUint(d []byte, offset int, v uint) []byte {
28 | bytes := size(v) / 8
29 |
30 | for i := 0; i < bytes; i++ {
31 | d[offset+bytes-1-i] = byte(v & 0xff)
32 | v >>= 8
33 | }
34 | return d
35 | }
36 |
37 | func GetUint256(d [32]byte) uint256 {
38 | return uint256(d[0])<<248 | uint256(d[1])<<240 | uint256(d[2])<<232 | uint256(d[3])<<224 | uint256(d[4])<<216 | uint256(d[5])<<208 | uint256(d[6])<<200| uint256(d[7])<<192 | uint256(d[8])<<184 | uint256(d[9])<<176 | uint256(d[10])<<168 | uint256(d[11])<<160 | uint256(d[12])<<152 | uint256(d[13])<<144 | uint256(d[14])<<136 | uint256(d[15])<<128 | uint256(d[16])<<120 | uint256(d[17])<<112 | uint256(d[18])<<104 | uint256(d[19])<<96 | uint256(d[20])<<88 | uint256(d[21])<<80 | uint256(d[22])<<72 | uint256(d[23])<<64 | uint256(d[24])<<56 | uint256(d[25])<<48 | uint256(d[26])<<40 | uint256(d[27])<<32 | uint256(d[28])<<24 | uint256(d[29])<<16 | uint256(d[30])<<8 | uint256(d[31])
39 | }
40 |
41 | // GetUint32 gets a MSB-encoded uint32 value from the argument buffer.
42 | func GetUint32(d []byte) uint32 {
43 | return uint32(d[0])<<24 | uint32(d[1])<<16 | uint32(d[2])<<8 | uint32(d[3])
44 | }
45 |
46 | // PutUint32 puts the uint32 value v to the buffer d starting from the
47 | // offset offset in MSB-order.
48 | func PutUint32(d []byte, offset int, v uint32) []byte {
49 | d[offset+0] = byte(v >> 24)
50 | d[offset+1] = byte(v >> 16)
51 | d[offset+2] = byte(v >> 8)
52 | d[offset+3] = byte(v)
53 | return d
54 | }
55 |
--------------------------------------------------------------------------------
/pkg/encoding/binary/littleendian.qcl:
--------------------------------------------------------------------------------
1 | package binary
2 |
3 | func LittleEndianUint16(b []byte) uint16 {
4 | _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
5 | return uint16(b[0]) | uint16(b[1])<<8
6 | }
7 |
8 | func LittleEndianPutUint16(b []byte, v uint16) {
9 | _ = b[1] // early bounds check to guarantee safety of writes below
10 | b[0] = byte(v)
11 | b[1] = byte(v >> 8)
12 | }
13 |
14 | func LittleEndianAppendUint16(b []byte, v uint16) []byte {
15 | return append(b, byte(v), byte(v>>8))
16 | }
17 |
18 | func LittleEndianUint32(b []byte) uint32 {
19 | _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
20 | return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
21 | }
22 |
23 | func LittleEndianPutUint32(b []byte, v uint32) {
24 | _ = b[3] // early bounds check to guarantee safety of writes below
25 | b[0] = byte(v)
26 | b[1] = byte(v >> 8)
27 | b[2] = byte(v >> 16)
28 | b[3] = byte(v >> 24)
29 | }
30 |
31 | func LittleEndianAppendUint32(b []byte, v uint32) []byte {
32 | return append(b, byte(v), byte(v>>8), byte(v>>16), byte(v>>24))
33 | }
34 |
35 | func LittleEndianUint64(b []byte) uint64 {
36 | a := b[7] // bounds check hint to compiler; see golang.org/issue/14808
37 | return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
38 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
39 | }
40 |
41 | func LittleEndianPutUint64(b []byte, v uint64) {
42 | a := b[7] // early bounds check to guarantee safety of writes below
43 | b[0] = byte(v)
44 | b[1] = byte(v >> 8)
45 | b[2] = byte(v >> 16)
46 | b[3] = byte(v >> 24)
47 | b[4] = byte(v >> 32)
48 | b[5] = byte(v >> 40)
49 | b[6] = byte(v >> 48)
50 | b[7] = byte(v >> 56)
51 | }
52 |
53 | func LittleEndianAppendUint64(b []byte, v uint64) []byte {
54 | return append(b, byte(v), byte(v>>8), byte(v>>16), byte(v>>24), byte(v>>32), byte(v>>40), byte(v>>48), byte(v>>56))
55 | }
--------------------------------------------------------------------------------
/pkg/encoding/binary/metrics.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package binary
9 |
10 | func HammingDistance(a, b uint) uint {
11 | return native("hamming", a, b)
12 | }
13 |
--------------------------------------------------------------------------------
/pkg/encoding/hex/doc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package hex implements hexadecimal encoding and decoding functions.
9 | package hex
10 |
--------------------------------------------------------------------------------
/pkg/encoding/hex/hex.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package hex
9 |
10 | import (
11 | "math"
12 | )
13 |
14 | // Digits define the hexadecimal ASCII digits (0-9, a-f).
15 | var Digits = []byte{
16 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
17 | 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
18 | }
19 |
20 | // DecodeString decodes the bytes represented by the hexadecimal
21 | // string s. The function returns also a boolean success value. The
22 | // success value is false if the input string length is not even or if
23 | // any of the runes in the input string are not valid hexadecimal
24 | // digits (0-9, a-f, A-F).
25 | func DecodeString(s string) ([]byte, bool) {
26 | result := make([]byte, len(s)/2)
27 |
28 | if len(s)%2 != 0 {
29 | return result, false
30 | }
31 | var lo, hi int32
32 | for i := 0; i < len(s); i += 2 {
33 | hi = DigitToByte(rune(s[i]))
34 | if hi > 0xff {
35 | return result, false
36 | }
37 | lo = DigitToByte(rune(s[i+1]))
38 | if lo > 0xff {
39 | return result, false
40 | }
41 | result[i/2] = hi<<4 | lo
42 | }
43 | return result, true
44 | }
45 |
46 | // DigitToByte converts the hexadecimal digit r to its byte value. The
47 | // return value is math.MaxInt32 if the input digit is invalid.
48 | func DigitToByte(r rune) int32 {
49 | if '0' <= r && r <= '9' {
50 | return r - '0'
51 | }
52 | if 'a' <= r && r <= 'f' {
53 | return r - 'a' + 10
54 | }
55 | if 'A' <= r && r <= 'F' {
56 | return r - 'A' + 10
57 | }
58 | return math.MaxInt32
59 | }
60 |
61 | // EncodeToString returns a hexadecimal encoding of src.
62 | func EncodeToString(src []byte) string {
63 | bytes := make([]byte, len(src)*2)
64 |
65 | for i := 0; i < len(src); i++ {
66 | bytes[i*2] = Digits[src[i]>>4]
67 | bytes[i*2+1] = Digits[src[i]&0xf]
68 | }
69 | return string(bytes)
70 | }
71 |
72 | // EncodedLen returns the length of an encoding of n source
73 | // bytes. Specifically, this returns n * 2.
74 | func EncodedLen(n int) int {
75 | return n * 2
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/math/const.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2023 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package math
9 |
10 | const (
11 | // MaxUint8 is the maximum unsigned 8-bit integer value.
12 | MaxUint8 = 0xff
13 | // MaxUint16 is the maximum unsigned 16-bit integer value.
14 | MaxUint16 = 0xffff
15 | // MaxUint32 is the maximum unsigned 32-bit integer value.
16 | MaxUint32 = 0xffffffff
17 | // MaxUint64 is the maximum unsigned 64-bit integer value.
18 | MaxUint64 = 0xffffffffffffffff
19 |
20 | // MaxInt32 is the maximum signed 8-bit integer value.
21 | MaxInt8 = 127
22 | // MaxInt32 is the maximum signed 16-bit integer value.
23 | MaxInt16 = 32767
24 | // MaxInt32 is the maximum signed 32-bit integer value.
25 | MaxInt32 = 2147483647
26 | // MaxInt32 is the maximum signed 64-bit integer value.
27 | MaxInt64 = 9223372036854775807
28 | )
29 |
--------------------------------------------------------------------------------
/pkg/math/doc.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package math implements various mathematical algorithms and
9 | // provides commonly used constant values.
10 | package math
11 |
--------------------------------------------------------------------------------
/pkg/math/integer.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package math
9 |
10 | // AddUint64 adds two unsigned 64-bit integer numbers.
11 | func AddUint64(a, b uint64) uint64 {
12 | return native("add64.circ", a, b)
13 | }
14 |
15 | // SubUint64 subtracts two unsigned 64-bit integer numbers.
16 | func SubUint64(a, b uint64) uint64 {
17 | return native("sub64.circ", a, b)
18 | }
19 |
20 | // MulUint64 multiplies two unsigned 64-bit integer numbers.
21 | func MulUint64(a, b uint64) uint64 {
22 | return native("mul64.circ", a, b)
23 | }
24 |
25 | // DivUint64 divides two unsigned 64-bit integer numbers.
26 | func DivUint64(a, b uint64) uint64 {
27 | return native("div64.circ", a, b)
28 | }
29 |
30 | // MaxUint returns the maximum of the argument unsigned integer numbers.
31 | func MaxUint(a, b uint) uint {
32 | if a > b {
33 | return a
34 | }
35 | return b
36 | }
37 |
38 | // MinUint returns the minimum of the argument unsigned integer numbers.
39 | func MinUint(a, b uint) uint {
40 | if a < b {
41 | return a
42 | }
43 | return b
44 | }
45 |
--------------------------------------------------------------------------------
/pkg/math/modp.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package math
9 |
10 | // Exp computes modular exponentiation b**e mod |m| (i.e. the sign of
11 | // m is ignore).
12 | func Exp(b, e, m uint) uint {
13 | rType := make(uint, size(m))
14 | mType := make(uint, size(m)*2)
15 |
16 | var r mType = 1
17 |
18 | for i := size(e) - 1; i >= 0; i = i - 1 {
19 | r = r * r % mType(m)
20 | if e>>i&1 != 0 {
21 | r = r * mType(b) % mType(m)
22 | }
23 | }
24 |
25 | return rType(r)
26 | }
27 |
--------------------------------------------------------------------------------
/pkg/math/montgomery.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2020-2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | package math
9 |
10 | func makeMontgomery(m uint) uint {
11 | n := size(m)
12 | tmpType := make(uint, size(m)*2+1)
13 | rrmType := make(uint, size(m))
14 |
15 | var tmp tmpType = 1
16 | tmp = (tmp << (n * 2)) % tmpType(m)
17 | return rrmType(tmp)
18 | }
19 |
20 | func reduce(m, rrm, t uint) uint {
21 | n := size(m)
22 | a := t
23 | aType := make(uint, size(a))
24 |
25 | for i := 0; i < n; i++ {
26 | if a&1 != 0 {
27 | a += aType(m)
28 | }
29 | a = a >> 1
30 | }
31 | if a >= aType(m) {
32 | a = a - aType(m)
33 | }
34 | return a
35 | }
36 |
37 | // ExpMontgomery computes modular exponentiation b**e mod |m|
38 | // (i.e. the sign of m is ignored). The m must be bigger than 0 and
39 | // not even number.
40 | func ExpMontgomery(b, e, m uint) uint {
41 | cType := make(uint, size(m)*2)
42 |
43 | rrm := makeMontgomery(m)
44 |
45 | t1 := cType(b) * cType(rrm)
46 | t2 := cType(e) * cType(rrm)
47 |
48 | r1 := math.reduce(m, rrm, t1)
49 | r2 := math.reduce(m, rrm, t2)
50 |
51 | prod := math.reduce(m, rrm, rrm)
52 | base := math.reduce(m, rrm, b*rrm)
53 |
54 | for i := 0; i < size(e); i++ {
55 | if e>>i&1 != 0 {
56 | prod = math.reduce(m, rrm, prod*base)
57 | }
58 | base = math.reduce(m, rrm, base*base)
59 | }
60 |
61 | return math.reduce(m, rrm, prod)
62 | }
63 |
--------------------------------------------------------------------------------
/pkg/sort/sort.qcl:
--------------------------------------------------------------------------------
1 | // -*- go -*-
2 | //
3 | // Copyright (c) 2021 Markku Rossi
4 | //
5 | // All rights reserved.
6 | //
7 |
8 | // Package sort implements array sorting functions.
9 | package sort
10 |
11 | // Reverse reverses the argument slice.
12 | func Reverse(arr []int) []int {
13 | tmp := arr[0]
14 | for i := 0; i < len(arr)/2; i++ {
15 | tmp = arr[i]
16 | arr[i] = arr[len(arr)-1-i]
17 | arr[len(arr)-1-i] = tmp
18 | }
19 | return arr
20 | }
21 |
22 | // Sort sorts the argument slice in ascending order.
23 | func Slice(arr []int) []int {
24 | return bitonicSort(arr, 0, len(arr), true)
25 | }
26 |
27 | func bitonicSort(a []int, lo, n int, dir bool) []int {
28 | if n > 1 {
29 | m := n / 2
30 | a = bitonicSort(a, lo, m, !dir)
31 | a = bitonicSort(a, lo+m, n-m, dir)
32 | a = bitonicMerge(a, lo, n, dir)
33 | }
34 | return a
35 | }
36 |
37 | func bitonicMerge(a []int, lo, n int, dir bool) []int {
38 | if n > 1 {
39 | m := floorPow2(n - 1)
40 | tmp := a[0]
41 | for i := lo; i < lo+n-m; i++ {
42 | if dir == (a[i] > a[i+m]) {
43 | tmp = a[i]
44 | a[i] = a[i+m]
45 | a[i+m] = tmp
46 | }
47 | }
48 | a = bitonicMerge(a, lo, m, dir)
49 | a = bitonicMerge(a, lo+m, n-m, dir)
50 | }
51 | return a
52 | }
53 |
--------------------------------------------------------------------------------
/types/parse.go:
--------------------------------------------------------------------------------
1 | //
2 | // parse.go
3 | //
4 | // Copyright (c) 2021-2023 Markku Rossi
5 | //
6 | // All rights reserved.
7 | //
8 |
9 | package types
10 |
11 | import (
12 | "fmt"
13 | "regexp"
14 | "strconv"
15 | )
16 |
17 | var (
18 | reArr = regexp.MustCompilePOSIX(`^\[([[:digit:]]+)\](.+)$`)
19 | reSized = regexp.MustCompilePOSIX(`^([[:^digit:]]+)([[:digit:]]*)$`)
20 | )
21 |
22 | // Parse parses type definition and returns its type information.
23 | func Parse(val string) (info Info, err error) {
24 | var ival int64
25 |
26 | switch val {
27 | case "b", "bool":
28 | info = Bool
29 | return
30 |
31 | case "byte":
32 | info = Byte
33 | return
34 |
35 | case "rune":
36 | info = Rune
37 | return
38 | }
39 |
40 | m := reSized.FindStringSubmatch(val)
41 | if m != nil {
42 | switch m[1] {
43 | case "b", "bool":
44 | info.Type = TBool
45 |
46 | case "i", "int":
47 | info.Type = TInt
48 |
49 | case "u", "uint":
50 | info.Type = TUint
51 |
52 | case "s", "string":
53 | info.Type = TString
54 |
55 | case "struct":
56 | info.Type = TStruct
57 |
58 | default:
59 | return info, fmt.Errorf("types.Parse: unknown type: %s", val)
60 | }
61 | var bits int64
62 | if len(m[2]) > 0 {
63 | bits, err = strconv.ParseInt(m[2], 10, 32)
64 | if err != nil {
65 | return
66 | }
67 | info.IsConcrete = true
68 | }
69 | info.Bits = Size(bits)
70 | info.MinBits = info.Bits
71 | return
72 | }
73 |
74 | m = reArr.FindStringSubmatch(val)
75 | if m == nil {
76 | return info, fmt.Errorf("types.Parse: unknown type: %s", val)
77 | }
78 | var elType Info
79 | elType, err = Parse(m[2])
80 | if err != nil {
81 | return
82 | }
83 | ival, err = strconv.ParseInt(m[1], 10, 32)
84 | if err != nil {
85 | return
86 | }
87 |
88 | info.Type = TArray
89 | info.IsConcrete = true
90 | info.Bits = Size(ival) * elType.Bits
91 | info.MinBits = info.Bits
92 | info.ElementType = &elType
93 | info.ArraySize = Size(ival)
94 |
95 | return
96 | }
97 |
--------------------------------------------------------------------------------
/types/parse_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2021-2023 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package types
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | var parseTests = []struct {
14 | input string
15 | info Info
16 | }{
17 | {
18 | input: "b",
19 | info: Bool,
20 | },
21 | {
22 | input: "bool",
23 | info: Bool,
24 | },
25 | {
26 | input: "byte",
27 | info: Byte,
28 | },
29 | {
30 | input: "rune",
31 | info: Rune,
32 | },
33 | {
34 | input: "i32",
35 | info: Int32,
36 | },
37 | {
38 | input: "int32",
39 | info: Int32,
40 | },
41 | {
42 | input: "u32",
43 | info: Uint32,
44 | },
45 | {
46 | input: "uint32",
47 | info: Uint32,
48 | },
49 | {
50 | input: "i32",
51 | info: Int32,
52 | },
53 | {
54 | input: "int32",
55 | info: Int32,
56 | },
57 | {
58 | input: "string8",
59 | info: Info{
60 | Type: TString,
61 | IsConcrete: true,
62 | Bits: 8,
63 | MinBits: 8,
64 | },
65 | },
66 | {
67 | input: "[8]byte",
68 | info: Info{
69 | Type: TArray,
70 | IsConcrete: true,
71 | Bits: 64,
72 | MinBits: 64,
73 | ElementType: &Info{
74 | Type: TUint,
75 | IsConcrete: true,
76 | Bits: 8,
77 | MinBits: 8,
78 | },
79 | ArraySize: 8,
80 | },
81 | },
82 | }
83 |
84 | func TestParse(t *testing.T) {
85 | for idx, test := range parseTests {
86 | info, err := Parse(test.input)
87 | if err != nil {
88 | t.Errorf("parseTest[%d]: %s\n", idx, err)
89 | continue
90 | }
91 | if !info.Equal(test.info) {
92 | t.Errorf("%v != %v", info, test.info)
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/types/types_test.go:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) 2020 Markku Rossi
3 | //
4 | // All rights reserved.
5 | //
6 |
7 | package types
8 |
9 | import (
10 | "testing"
11 | )
12 |
13 | func TestUndefined(t *testing.T) {
14 | undef := Info{}
15 | if !undef.Undefined() {
16 | t.Errorf("undef is not undefined")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------