Skip to content

Commit

Permalink
Merge pull request #31 from markkurossi/topic/copy
Browse files Browse the repository at this point in the history
Topic/copy
  • Loading branch information
markkurossi authored Jul 25, 2024
2 parents d3b2ce0 + 6c5c269 commit b51c3bd
Show file tree
Hide file tree
Showing 20 changed files with 407 additions and 337 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ The MPCL runtime defines the following builtin functions:
- [ ] SSA aliasing is 1:1 but `amov` has 2:1 relation
- [ ] variable liveness analysis for templates
- [ ] BitShift
- [ ] `copy()` does not work on arrays which have been `make()`:ed
- [x] `copy()` does not work on arrays which have been `make()`:ed
- [ ] `&base[pos][i]` returns the address of the first element
- [ ] reading from `*[32]int32` returns invalid values
- [x] Pointer handling
Expand Down
23 changes: 13 additions & 10 deletions apps/garbled/examples/aescbc.mpcl
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ import (
)

// Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key
// Key : 0x06a9214036b8a15b512e03d534120006
// IV : 0x3dafba429d9eb430b422da802c9fac41
// Plaintext : "Single block msg"
// Ciphertext: 0xe353779c1079aeb82708942dbe77181a
//
// Key : 0x06a9214036b8a15b512e03d534120006
// IV : 0x3dafba429d9eb430b422da802c9fac41
// Plaintext : "Single block msg"
// Ciphertext: 0xe353779c1079aeb82708942dbe77181a
//
// Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with 128-bit key
// Key : 0xc286696d887c9aa0611bbb3e2025a45a
// IV : 0x562e17996d093d28ddb3ba695a2e6f58
// Plaintext : 0x000102030405060708090a0b0c0d0e0f
// 101112131415161718191a1b1c1d1e1f
// Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
// 7586602d253cfff91b8266bea6d61ab1
//
// Key : 0xc286696d887c9aa0611bbb3e2025a45a
// IV : 0x562e17996d093d28ddb3ba695a2e6f58
// Plaintext : 0x000102030405060708090a0b0c0d0e0f
// 101112131415161718191a1b1c1d1e1f
// Ciphertext: 0xd296cd94c2cccf8a3a863028b5e1dc0a
//
// 7586602d253cfff91b8266bea6d61ab1
func main(g, e [16]byte) []byte {
key := []byte{
0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
Expand Down
12 changes: 12 additions & 0 deletions compiler/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var (
_ AST = &BasicLit{}
_ AST = &CompositeLit{}
_ AST = &Make{}
_ AST = &Copy{}
)

func indent(w io.Writer, indent int) {
Expand Down Expand Up @@ -904,3 +905,14 @@ func (ast *Make) String() string {
}
return str + ")"
}

// Copy implements the builtin function copy.
type Copy struct {
utils.Point
Dst AST
Src AST
}

func (ast *Copy) String() string {
return fmt.Sprintf("copy(%v, %v)", ast.Dst, ast.Src)
}
111 changes: 0 additions & 111 deletions compiler/ast/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ type Eval func(args []AST, env *Env, ctx *Codegen, gen *ssa.Generator,

// Predeclared identifiers.
var builtins = map[string]Builtin{
"copy": {
SSA: copySSA,
},
"floorPow2": {
SSA: floorPow2SSA,
Eval: floorPow2Eval,
Expand All @@ -57,114 +54,6 @@ var builtins = map[string]Builtin{
},
}

func copySSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator,
args []ssa.Value, loc utils.Point) (*ssa.Block, []ssa.Value, error) {

if len(args) != 2 {
return nil, nil, ctx.Errorf(loc,
"invalid amount of arguments in call to copy")
}
dst := args[0]
src := args[1]

var baseName string
var baseType types.Info
var baseScope ssa.Scope
var baseBindings *ssa.Bindings
var base ssa.Value

var dstOffset types.Size
var elementType types.Info

switch dst.Type.Type {
case types.TArray, types.TSlice:
baseName = dst.Name
baseType = dst.Type
baseScope = dst.Scope
baseBindings = block.Bindings

dstOffset = 0
elementType = *dst.Type.ElementType
base = dst

case types.TPtr:
elementType = *dst.Type.ElementType
if !elementType.Type.Array() {
return nil, nil, ctx.Errorf(loc, "setting elements of non-array %s",
elementType)
}
baseName = dst.PtrInfo.Name
baseType = dst.PtrInfo.ContainerType
baseScope = dst.PtrInfo.Scope
baseBindings = dst.PtrInfo.Bindings

dstOffset = dst.PtrInfo.Offset
elementType = *elementType.ElementType

b, ok := baseBindings.Get(baseName)
if !ok {
return nil, nil, ctx.Errorf(loc, "undefined: %s", baseName)
}
base = b.Value(block, gen)

default:
return nil, nil, ctx.Errorf(loc,
"arguments to copy must be slices; have %s, %s",
dst.Type.Type, src.Type.Type)
}

var srcType types.Info
if src.Type.Type == types.TPtr {
srcType = *src.Type.ElementType
} else {
srcType = src.Type
}

if !srcType.Type.Array() {
return nil, nil, ctx.Errorf(loc,
"second argument to copy should be slice or array (%v)", src.Type)
}
if !elementType.Equal(*srcType.ElementType) {
return nil, nil, ctx.Errorf(loc,
"arguments to copy have different element types: %s and %s",
baseType.ElementType, src.Type.ElementType)
}

dstBits := dst.Type.Bits
srcBits := src.Type.Bits

var copied types.Size
if srcBits > dstBits {
fromConst := gen.Constant(int64(0), types.Undefined)
toConst := gen.Constant(int64(dstBits), types.Undefined)

tmp := gen.AnonVal(dst.Type)
block.AddInstr(ssa.NewSliceInstr(src, fromConst, toConst, tmp))
src = tmp
srcBits = dstBits

copied = dst.Type.ArraySize
} else {
copied = src.Type.ArraySize
}

lValue := gen.NewVal(baseName, baseType, baseScope)

fromConst := gen.Constant(int64(dstOffset), types.Undefined)
toConst := gen.Constant(int64(dstOffset+srcBits), types.Undefined)

block.AddInstr(ssa.NewAmovInstr(src, base, fromConst, toConst, lValue))
err := baseBindings.Set(lValue, nil)
if err != nil {
return nil, nil, ctx.Error(loc, err.Error())
}

v := gen.Constant(int64(copied), types.Undefined)
gen.AddConstant(v)

return block, []ssa.Value{v}, nil
}

func floorPow2SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator,
args []ssa.Value, loc utils.Point) (*ssa.Block, []ssa.Value, error) {
return nil, nil, ctx.Errorf(loc, "floorPow2SSA not implemented")
Expand Down
18 changes: 13 additions & 5 deletions compiler/ast/codegen.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// ast.go
//
// Copyright (c) 2019-2023 Markku Rossi
// Copyright (c) 2019-2024 Markku Rossi
//
// All rights reserved.
//
Expand All @@ -11,6 +11,7 @@ package ast
import (
"fmt"
"runtime"
"strings"

"github.com/markkurossi/mpc/circuit"
"github.com/markkurossi/mpc/compiler/ssa"
Expand Down Expand Up @@ -53,12 +54,19 @@ func (ctx *Codegen) errorLoc(err error) error {
if !ctx.Params.MPCLCErrorLoc {
return err
}
_, file, line, ok := runtime.Caller(2)
if !ok {

for skip := 2; ; skip++ {
pc, file, line, ok := runtime.Caller(skip)
if !ok {
return err
}
f := runtime.FuncForPC(pc)
if f != nil && strings.HasSuffix(f.Name(), ".errf") {
continue
}
fmt.Printf("%s:%d: MCPLC error:\n\u2514\u2574%s\n", file, line, err)
return err
}
fmt.Printf("%s:%d: MCPLC error:\n\u2514\u2574%s\n", file, line, err)
return err
}

// Error logs an error message.
Expand Down
75 changes: 42 additions & 33 deletions compiler/ast/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const (
// Eval implements the compiler.ast.AST.Eval for list statements.
func (ast List) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
ssa.Value, bool, error) {
return ssa.Undefined, false, fmt.Errorf("List.Eval not implemented yet")
return ssa.Undefined, false, ctx.Errorf(ast, "List.Eval not implemented")
}

// Eval implements the compiler.ast.AST.Eval for function definitions.
Expand Down Expand Up @@ -453,42 +453,45 @@ func (ast *Slice) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
return ssa.Undefined, false, ctx.Errorf(ast.Expr,
"invalid slice range %d:%d", from, to)
}
switch expr.Type.Type {
case types.TArray, types.TSlice:
arr, err := expr.ConstArray()
if err != nil {
return ssa.Undefined, false, err
}
if to == math.MaxInt32 {
to = int(expr.Type.ArraySize)
}
if to > int(expr.Type.ArraySize) || from > to {
return ssa.Undefined, false, ctx.Errorf(ast.From,
"slice bounds out of range [%d:%d] in slice of length %v",
from, to, expr.Type.ArraySize)
}
numElements := to - from
if !expr.Type.Type.Array() {
return ssa.Undefined, false, ctx.Errorf(ast.Expr,
"invalid operation: cannot slice %v (%v)", expr, expr.Type)
}
arr, err := expr.ConstArray()
if err != nil {
return ssa.Undefined, false, err
}
if to == math.MaxInt32 {
to = int(expr.Type.ArraySize)
}
if to > int(expr.Type.ArraySize) || from > to {
return ssa.Undefined, false, ctx.Errorf(ast.From,
"slice bounds out of range [%d:%d] in slice of length %v",
from, to, expr.Type.ArraySize)
}
numElements := to - from

switch val := arr.(type) {
case []interface{}:
ti := expr.Type
ti.ArraySize = types.Size(numElements)
// The gen.Constant will set the bit sizes.
return gen.Constant(val[from:to], ti), true, nil
switch val := arr.(type) {
case []interface{}:
ti := expr.Type
ti.ArraySize = types.Size(numElements)
// The gen.Constant will set the bit sizes.
return gen.Constant(val[from:to], ti), true, nil

case []byte:
constVal := make([]interface{}, numElements)
for i := 0; i < numElements; i++ {
constVal[i] = int64(val[from+i])
}
ti := expr.Type
ti.ArraySize = types.Size(numElements)
// The gen.Constant will set the bit sizes.
return gen.Constant(constVal, ti), true, nil
case []byte:
constVal := make([]interface{}, numElements)
for i := 0; i < numElements; i++ {
constVal[i] = int64(val[from+i])
}
ti := expr.Type
ti.ArraySize = types.Size(numElements)
// The gen.Constant will set the bit sizes.
return gen.Constant(constVal, ti), true, nil

default:
return ssa.Undefined, false, ctx.Errorf(ast.Expr,
"invalid operation: cannot slice %T array", arr)
}
return ssa.Undefined, false, ctx.Errorf(ast.Expr,
"invalid operation: cannot slice %v (%v)", expr, expr.Type)
}

func intVal(val interface{}) (int, error) {
Expand Down Expand Up @@ -673,3 +676,9 @@ func (ast *Make) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
// Create typeref constant.
return gen.Constant(typeInfo, types.Undefined), true, nil
}

// Eval implements the compiler.ast.AST.Eval for the builtin function copy.
func (ast *Copy) Eval(env *Env, ctx *Codegen, gen *ssa.Generator) (
ssa.Value, bool, error) {
return ssa.Undefined, false, nil
}
34 changes: 33 additions & 1 deletion compiler/ast/lrvalue.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,38 @@ func (lrv *LRValue) BasePtrInfo() *ssa.PtrInfo {
return lrv.baseInfo
}

// Indirect returns LRValue for the value that lrv points to. If lrv
// is not a pointer, Indirect returns lrv.
func (lrv *LRValue) Indirect() *LRValue {
v := lrv.RValue()
if v.Type.Type != types.TPtr {
return lrv
}

ret := *lrv
ret.valueType = *lrv.valueType.ElementType
ret.value.PtrInfo = nil

if lrv.baseInfo.ContainerType.Type == types.TStruct {
ret.value.Type = types.Undefined

// Lookup struct field.
ret.structField = nil
for _, f := range lrv.baseValue.Type.Struct {
if f.Type.Offset == lrv.baseInfo.Offset {
ret.structField = &f
}
}
if ret.structField == nil {
panic("LRValue.Indirect: could not find struct field")
}
} else {
ret.value.Type = *lrv.value.Type.ElementType
}

return &ret
}

// Set sets the l-value to rv.
func (lrv LRValue) Set(rv ssa.Value) error {
if !ssa.CanAssign(lrv.valueType, rv) {
Expand Down Expand Up @@ -123,7 +155,7 @@ func (lrv LRValue) Set(rv ssa.Value) error {
// The l-value and r-value types are now resolved. Let's define
// the variable with correct type and value information,
// overriding any old values.
lrv.block.Bindings.Define(lValue, &rv)
lrv.baseInfo.Bindings.Define(lValue, &rv)

return nil
}
Expand Down
Loading

0 comments on commit b51c3bd

Please sign in to comment.