├── 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 = ` 14 | 17 | 20 | 21 | 25 | 29 | 30 | 31 | 35 | 39 | 43 | 44 | ` 45 | 46 | var tmplXORExpanded = ` 47 | 50 | 53 | 54 | 58 | 62 | 63 | 64 | 68 | 72 | 76 | 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 | --------------------------------------------------------------------------------