diff --git a/README.md b/README.md index 83e67565..3d29058d 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/apps/garbled/examples/aescbc.mpcl b/apps/garbled/examples/aescbc.mpcl index 061eef5e..0654121c 100644 --- a/apps/garbled/examples/aescbc.mpcl +++ b/apps/garbled/examples/aescbc.mpcl @@ -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, diff --git a/compiler/ast/ast.go b/compiler/ast/ast.go index 054c72d7..e641aa24 100644 --- a/compiler/ast/ast.go +++ b/compiler/ast/ast.go @@ -39,6 +39,7 @@ var ( _ AST = &BasicLit{} _ AST = &CompositeLit{} _ AST = &Make{} + _ AST = &Copy{} ) func indent(w io.Writer, indent int) { @@ -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) +} diff --git a/compiler/ast/builtin.go b/compiler/ast/builtin.go index e1f1bc63..6f0c2e9d 100644 --- a/compiler/ast/builtin.go +++ b/compiler/ast/builtin.go @@ -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, @@ -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") diff --git a/compiler/ast/codegen.go b/compiler/ast/codegen.go index 1e21d50a..c43b017a 100644 --- a/compiler/ast/codegen.go +++ b/compiler/ast/codegen.go @@ -1,7 +1,7 @@ // // ast.go // -// Copyright (c) 2019-2023 Markku Rossi +// Copyright (c) 2019-2024 Markku Rossi // // All rights reserved. // @@ -11,6 +11,7 @@ package ast import ( "fmt" "runtime" + "strings" "github.com/markkurossi/mpc/circuit" "github.com/markkurossi/mpc/compiler/ssa" @@ -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. diff --git a/compiler/ast/eval.go b/compiler/ast/eval.go index aa767fce..ff3f2a68 100644 --- a/compiler/ast/eval.go +++ b/compiler/ast/eval.go @@ -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. @@ -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) { @@ -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 +} diff --git a/compiler/ast/lrvalue.go b/compiler/ast/lrvalue.go index 6401cf79..e4a4c838 100644 --- a/compiler/ast/lrvalue.go +++ b/compiler/ast/lrvalue.go @@ -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) { @@ -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 } diff --git a/compiler/ast/ssagen.go b/compiler/ast/ssagen.go index a87023a1..c1eaffc8 100644 --- a/compiler/ast/ssagen.go +++ b/compiler/ast/ssagen.go @@ -1833,62 +1833,17 @@ func (ast *Slice) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( return nil, nil, ctx.Errorf(ast, "invalid expression") } expr := exprs[0] - elementType := expr.ElementType() - - var elementSize types.Size - var elementCount types.Size - - switch elementType.Type { - case types.TInt, types.TUint: - elementSize = 1 - elementCount = elementType.Bits - - case types.TArray, types.TSlice: - elementSize = elementType.ElementType.Bits - elementCount = elementType.ArraySize - - default: - return nil, nil, ctx.Errorf(ast, "slice of %s not supported", + elementType := expr.IndirectType() + if !elementType.Type.Array() { + return nil, nil, ctx.Errorf(ast, "invalid operation: cannot slice %v", expr.Type.Type) } + elementSize := elementType.ElementType.Bits - var val []ssa.Value - var from types.Size - if ast.From == nil { - from = 0 - } else { - block, val, err = ast.From.SSA(block, ctx, gen) - if err != nil { - return nil, nil, err - } - if len(val) != 1 { - return nil, nil, ctx.Errorf(ast.From, "invalid from index") - } - from, err = val[0].ConstInt() - if err != nil { - return nil, nil, ctx.Errorf(ast.From, "%s", err) - } - } - var to types.Size - if ast.To == nil { - to = elementCount - } else { - block, val, err = ast.To.SSA(block, ctx, gen) - if err != nil { - return nil, nil, err - } - if len(val) != 1 { - return nil, nil, ctx.Errorf(ast.To, "invalid to index") - } - to, err = val[0].ConstInt() - if err != nil { - return nil, nil, ctx.Errorf(ast.To, "%s", err) - } - } - if ast.From != nil && ast.To != nil && - (from >= elementCount || from > to) { - return nil, nil, ctx.Errorf(ast, "slice bounds out of range [%d:%d]", - from, to) + var from, to types.Size + block, from, to, err = ast.limitsSSA(block, ctx, gen, elementType) + if err != nil { + return nil, nil, err } bits := (to - from) * elementSize @@ -1943,6 +1898,55 @@ func (ast *Slice) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( return block, []ssa.Value{t}, nil } +func (ast *Slice) limitsSSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator, + t types.Info) (*ssa.Block, types.Size, types.Size, error) { + + elementCount := t.ArraySize + + var err error + var val []ssa.Value + var from types.Size + + if ast.From == nil { + from = 0 + } else { + block, val, err = ast.From.SSA(block, ctx, gen) + if err != nil { + return nil, 0, 0, err + } + if len(val) != 1 { + return nil, 0, 0, ctx.Errorf(ast.From, "invalid from index") + } + from, err = val[0].ConstInt() + if err != nil { + return nil, 0, 0, ctx.Errorf(ast.From, "%s", err) + } + } + var to types.Size + if ast.To == nil { + to = elementCount + } else { + block, val, err = ast.To.SSA(block, ctx, gen) + if err != nil { + return nil, 0, 0, err + } + if len(val) != 1 { + return nil, 0, 0, ctx.Errorf(ast.To, "invalid to index") + } + to, err = val[0].ConstInt() + if err != nil { + return nil, 0, 0, ctx.Errorf(ast.To, "%s", err) + } + } + if ast.From != nil && ast.To != nil && + (from >= elementCount || from > to) { + return nil, 0, 0, ctx.Errorf(ast, "slice bounds out of range [%d:%d]", + from, to) + } + + return block, from, to, nil +} + // SSA implements the compiler.ast.AST.SSA for index expressions. func (ast *Index) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( *ssa.Block, []ssa.Value, error) { @@ -2161,3 +2165,133 @@ func (ast *Make) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( return block, []ssa.Value{v}, nil } + +// SSA implements the compiler.ast.AST.SSA for the builtin function copy. +func (ast *Copy) SSA(block *ssa.Block, ctx *Codegen, gen *ssa.Generator) ( + *ssa.Block, []ssa.Value, error) { + + var lrv *LRValue + var err error + var dst ssa.Value + var dstTo, dstFrom types.Size + + // Resolve destination. + switch lv := ast.Dst.(type) { + case *VariableRef: + lrv, _, _, err = ctx.LookupVar(block, gen, block.Bindings, lv) + if err != nil { + return nil, nil, ctx.Error(ast.Dst, err.Error()) + } + lrv = lrv.Indirect() + dst = lrv.RValue() + if !dst.Type.Type.Array() { + return nil, nil, ast.errf(ctx, ast.Dst, "got %v", dst.Type) + } + dstFrom = 0 + dstTo = dst.Type.ArraySize + + case *Slice: + // Slice specifies the copy limits for the + // destination. Slice's expr must be a variable reference. + sexpr, ok := lv.Expr.(*VariableRef) + if !ok { + return nil, nil, ast.errf(ctx, ast.Dst, "got %T", lv.Expr) + } + lrv, _, _, err = ctx.LookupVar(block, gen, block.Bindings, sexpr) + if err != nil { + return nil, nil, ctx.Error(ast.Dst, err.Error()) + } + lrv = lrv.Indirect() + dst = lrv.RValue() + if !dst.Type.Type.Array() { + return nil, nil, ast.errf(ctx, ast.Dst, "got %v", dst.Type) + } + + block, dstFrom, dstTo, err = lv.limitsSSA(block, ctx, gen, dst.Type) + if err != nil { + return nil, nil, ctx.Error(ast.Dst, err.Error()) + } + + default: + return nil, nil, ast.errf(ctx, ast.Dst, "got %T", ast.Dst) + } + dstCount := dstTo - dstFrom + elSize := dst.Type.ElementType.Bits + + // Resolve source. + block, v, err := ast.Src.SSA(block, ctx, gen) + if err != nil { + return nil, nil, err + } + if len(v) != 1 { + return nil, nil, ast.errf(ctx, ast.Src, "got multivalue %T", ast.Src) + } + src := v[0] + srcType := src.IndirectType() + if !srcType.Type.Array() { + return nil, nil, ast.errf(ctx, ast.Src, "got %v", src.Type) + } + if !dst.Type.ElementType.Equal(*srcType.ElementType) { + return nil, nil, ctx.Errorf(ast, + "arguments to copy have different element types: %s and %s", + dst.Type.ElementType, src.Type.ElementType) + } + srcCount := src.Type.ArraySize + + var ret ssa.Value + + if dstFrom == 0 && srcCount >= dstCount { + // Src overwrites dst fully. + bits := dstCount * elSize + ti := types.Info{ + Type: dst.Type.Type, + IsConcrete: true, + Bits: bits, + MinBits: bits, + ElementType: dst.Type.ElementType, + ArraySize: dstCount, + } + fromConst := gen.Constant(int64(0), types.Undefined) + toConst := gen.Constant(int64(dstCount*elSize), types.Undefined) + ret = gen.Constant(int64(dstCount), types.Undefined) + + tmp := gen.AnonVal(ti) + block.AddInstr(ssa.NewSliceInstr(src, fromConst, toConst, tmp)) + err := lrv.Set(tmp) + if err != nil { + return nil, nil, ctx.Error(ast, err.Error()) + } + } else { + // Src overwrites part of dst. + tmp := gen.AnonVal(dst.Type) + block.AddInstr(ssa.NewMovInstr(dst, tmp)) + + count := srcCount + if count > dstCount { + count = dstCount + } + ret = gen.Constant(int64(count), types.Undefined) + + // The amov sets tmp[from:to]=src i.e. it automatically slices + // src to to-from bits. + + tmp2 := gen.AnonVal(dst.Type) + fromConst := gen.Constant(int64(dstFrom*elSize), types.Undefined) + toConst := gen.Constant(int64((dstFrom+count)*elSize), types.Undefined) + block.AddInstr(ssa.NewAmovInstr(src, tmp, fromConst, toConst, tmp2)) + + err := lrv.Set(tmp2) + if err != nil { + return nil, nil, ctx.Error(ast, err.Error()) + } + } + + return block, []ssa.Value{ret}, nil +} + +func (ast *Copy) errf(ctx *Codegen, offending AST, format string, + a ...interface{}) error { + msg := fmt.Sprintf(format, a...) + return ctx.Errorf(offending, + "invalid argument: copy expects slice arguments: %s", msg) +} diff --git a/compiler/parser.go b/compiler/parser.go index 32c2d0a2..c4d72ef9 100644 --- a/compiler/parser.go +++ b/compiler/parser.go @@ -1431,6 +1431,17 @@ primary: Type: ti, Exprs: arguments, } + } else if vr.String() == "copy" { + if len(arguments) != 2 { + return nil, p.errf(primary.Location(), + "invalid arguments for copy (expected 2, found %v)", + len(arguments)) + } + primary = &ast.Copy{ + Point: primary.Location(), + Dst: arguments[0], + Src: arguments[1], + } } else { primary = &ast.Call{ Point: primary.Location(), diff --git a/compiler/ssa/value.go b/compiler/ssa/value.go index 60e688bd..f402974f 100644 --- a/compiler/ssa/value.go +++ b/compiler/ssa/value.go @@ -75,9 +75,9 @@ func (v Value) Check() { } } -// ElementType returns the pointer element type of the value. For -// non-pointer values, this returns the value type itself. -func (v Value) ElementType() types.Info { +// IndirectType returns the type that v points to. If v is not a +// pointer, IndirectType returns the type of v. +func (v Value) IndirectType() types.Info { if v.Type.Type == types.TPtr { return *v.Type.ElementType } diff --git a/pkg/crypto/cipher/cbc/cbc.mpcl b/pkg/crypto/cipher/cbc/cbc.mpcl index 32619864..48256235 100644 --- a/pkg/crypto/cipher/cbc/cbc.mpcl +++ b/pkg/crypto/cipher/cbc/cbc.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2021 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // All rights reserved. // @@ -24,7 +24,7 @@ func PadAES(data []byte) []byte { for i := 0; i < padLen; i++ { padded[len(data)+i] = byte(padLen) } - padded = memcpy(padded, 0, data, 0) + copy(padded, data) return padded } @@ -33,40 +33,39 @@ func PadAES(data []byte) []byte { // the AES encryption key and iv is a random initialization // vector. The data must be padded to AES block size. // -// // Case #1: Encrypting 16 bytes (1 block) using AES-CBC with 128-bit key -// // Key : 0x06a9214036b8a15b512e03d534120006 -// // IV : 0x3dafba429d9eb430b422da802c9fac41 -// // Plaintext : "Single block msg" -// // Ciphertext: 0xe353779c1079aeb82708942dbe77181a +// // 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 := []byte{ -// 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, -// 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06, -// } -// iv := []byte{ -// 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, -// 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41, -// } -// plain := []byte("Single block msg") -// -// cipher := cbc.EncryptAES128(key, iv, plain) -// => e353779c1079aeb82708942dbe77181a +// key := []byte{ +// 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, +// 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06, +// } +// iv := []byte{ +// 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, +// 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41, +// } +// plain := []byte("Single block msg") // +// cipher := cbc.EncryptAES128(key, iv, plain) +// => e353779c1079aeb82708942dbe77181a func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { var block [aes.BlockSize]byte - block = memcpy(block, 0, iv, 0) + copy(block, iv) var plain [aes.BlockSize]byte var cipher [len(data)]byte for i := 0; i < len(data)/aes.BlockSize; i++ { - plain = memcpy(plain, 0, data, i*aes.BlockSize) + copy(plain, data[i*aes.BlockSize:]) for j := 0; j < aes.BlockSize; j++ { plain[j] ^= block[j] } //block = aes.Block128(key, plain) block = aes.EncryptBlock(key, plain) - cipher = memcpy(cipher, i*aes.BlockSize, block, 0) + copy(cipher[i*aes.BlockSize:], block) } return cipher @@ -79,21 +78,14 @@ func DecryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { var plain [len(data)]byte for i := 0; i < len(data)/aes.BlockSize; i++ { - cipher = memcpy(cipher, 0, data, i*aes.BlockSize) + copy(cipher, data[i*aes.BlockSize:]) block = aes.DecryptBlock(key, cipher) for j := 0; j < aes.BlockSize; j++ { block[j] ^= iv[j] } - plain = memcpy(plain, i*aes.BlockSize, block, 0) - iv = memcpy(iv, 0, cipher, 0) + copy(plain[i*aes.BlockSize:], block) + copy(iv, cipher) } return plain } - -func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte { - for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ { - dst[dstOfs+i] = src[srcOfs+i] - } - return dst -} diff --git a/pkg/crypto/cipher/cts/cts.mpcl b/pkg/crypto/cipher/cts/cts.mpcl index 143f08b4..e262c970 100644 --- a/pkg/crypto/cipher/cts/cts.mpcl +++ b/pkg/crypto/cipher/cts/cts.mpcl @@ -42,29 +42,29 @@ func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { panic("cts.EncryptAES128: input must be at least 2 block") } var block [aes.BlockSize]byte - block = memcpy(block, 0, iv, 0) + copy(block, iv) var plain [aes.BlockSize]byte var cipher [len(data)]byte // Standard CBC for the first numBlocks-1 blocks. for i := 0; i < numBlocks-1; i++ { - plain = memcpy(plain, 0, data, i*aes.BlockSize) + copy(plain, data[i*aes.BlockSize:]) for j := 0; j < aes.BlockSize; j++ { plain[j] ^= block[j] } block = aes.EncryptBlock(key, plain) if i < numBlocks-2 { // Store standard CBC output block. - cipher = memcpy(cipher, i*aes.BlockSize, block, 0) + copy(cipher[i*aes.BlockSize:], block) } else { // Store last ciphertext block. - cipher = memcpy(cipher, (numBlocks-1)*aes.BlockSize, block, 0) + copy(cipher[(numBlocks-1)*aes.BlockSize:], block) } } // Create last input block. - plain = memcpy(plain, 0, data, (numBlocks-1)*aes.BlockSize) + copy(plain, data[(numBlocks-1)*aes.BlockSize:]) for i := tail; i < aes.BlockSize; i++ { plain[i] = 0 } @@ -72,7 +72,7 @@ func EncryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { plain[j] ^= block[j] } block = aes.EncryptBlock(key, plain) - cipher = memcpy(cipher, (numBlocks-2)*aes.BlockSize, block, 0) + copy(cipher[(numBlocks-2)*aes.BlockSize:], block) return cipher } @@ -100,43 +100,36 @@ func DecryptAES128(key [16]byte, iv [aes.BlockSize]byte, data []byte) []byte { // Standard CBC for the first numBlocks-2 blocks. for i := 0; i < numBlocks-2; i++ { - cipher = memcpy(cipher, 0, data, i*aes.Blocks) + copy(cipher, data[i*aes.Blocks:]) block = aes.DecryptBlock(key, cipher) for j := 0; j < aes.BlockSize; j++ { block[j] ^= iv[j] } - plain = memcpy(plain, i*aes.BlockSize, block, 0) - iv = memcpy(iv, 0, cipher, 0) + copy(plain[i*aes.BlockSize:], block) + copy(iv, cipher) } // Decrypt second-to-last cipher block. - cipher = memcpy(cipher, 0, data, (numBlocks-2)*aes.BlockSize) + copy(cipher, data[(numBlocks-2)*aes.BlockSize:]) tmp := aes.DecryptBlock(key, cipher) // Create padded last cipher block. - tmp2 = memcpy(tmp2, 0, data, (numBlocks-1)*aes.BlockSize) - tmp2 = memcpy(tmp2, tail, tmp, tail) + copy(tmp2, data[(numBlocks-1)*aes.BlockSize:]) + copy(tmp2[tail:], tmp[tail:]) // Decrypt second-to-last block. block = aes.DecryptBlock(key, tmp2) for j := 0; j < aes.BlockSize; j++ { block[j] ^= iv[j] } - plain = memcpy(plain, (numBlocks-2)*aes.BlockSize, block, 0) - iv = memcpy(iv, 0, tmp2, 0) + copy(plain[(numBlocks-2)*aes.BlockSize:], block) + copy(iv, tmp2) // Finalize last block. for j := 0; j < aes.BlockSize; j++ { tmp[j] ^= iv[j] } - plain = memcpy(plain, (numBlocks-1)*aes.BlockSize, tmp, 0) + copy(plain[(numBlocks-1)*aes.BlockSize:], tmp) return plain } - -func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte { - for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ { - dst[dstOfs+i] = src[srcOfs+i] - } - return dst -} diff --git a/pkg/crypto/cipher/gcm/gcm.mpcl b/pkg/crypto/cipher/gcm/gcm.mpcl index a764ac77..9951778e 100644 --- a/pkg/crypto/cipher/gcm/gcm.mpcl +++ b/pkg/crypto/cipher/gcm/gcm.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2021-2023 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // All rights reserved. // @@ -31,7 +31,7 @@ func EncryptAES128(key [16]byte, nonce [NonceSize]byte, var counter [aes.BlockSize]byte - counter = memcpy(counter, 0, nonce, 0) + copy(counter, nonce) counter = incr(counter) e0 := byteToUint128(aes.Block128(key, counter)) @@ -104,7 +104,7 @@ func DecryptAES128(key [16]byte, nonce [NonceSize]byte, var counter [aes.BlockSize]byte - counter = memcpy(counter, 0, nonce, 0) + copy(counter, nonce) counter = incr(counter) e0 := byteToUint128(aes.Block128(key, counter)) @@ -229,10 +229,3 @@ func multGF2Pow128(x, y uint128) uint128 { } return z } - -func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte { - for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ { - dst[dstOfs+i] = src[srcOfs+i] - } - return dst -} diff --git a/pkg/crypto/ed25519/keygen.mpcl b/pkg/crypto/ed25519/keygen.mpcl index 0ae04022..59365061 100644 --- a/pkg/crypto/ed25519/keygen.mpcl +++ b/pkg/crypto/ed25519/keygen.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2021 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // Ed25519 key generation in MPCL. This file is derived from Go's // crypto/ed25519 package. The original copyright notice follows: @@ -27,14 +27,14 @@ func NewKeyFromSeed(seed [SeedSize]byte) (PublicKey, PrivateKey) { var A edwards25519.ExtendedGroupElement var hBytes [32]byte - hBytes = memcpy(hBytes, 0, digest, 0) + copy(hBytes, digest) edwards25519.GeScalarMultBase(&A, &hBytes) var publicKeyBytes [32]byte A.ToBytes(&publicKeyBytes) var privateKey [64]byte - privateKey = memcpy(privateKey, 0, seed, 0) - privateKey = memcpy(privateKey, 32, publicKeyBytes, 0) + copy(privateKey, seed) + copy(privateKey[32:], publicKeyBytes) return publicKeyBytes, privateKey } diff --git a/pkg/crypto/ed25519/sign.mpcl b/pkg/crypto/ed25519/sign.mpcl index 9c5e1c5d..71eee4c4 100644 --- a/pkg/crypto/ed25519/sign.mpcl +++ b/pkg/crypto/ed25519/sign.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2021-2023 Markku Rossi +// Copyright (c) 2021-2024 Markku Rossi // // Ed25519 signature computation in MPCL. This file is derived from // Go's crypto/ed25519 package. The original copyright notice follows: @@ -43,14 +43,14 @@ func Sign(privateKey PrivateKey, message []byte) []byte { digest1 := sha512.Sum512(privateKey[0:32]) var expandedSecretKey [32]byte - expandedSecretKey = memcpy(expandedSecretKey, 0, digest1, 0) + copy(expandedSecretKey, digest1) expandedSecretKey[0] &= 248 expandedSecretKey[31] &= 63 expandedSecretKey[31] |= 64 buf := make([]byte, 32+len(message)) - buf = memcpy(buf, 0, digest1, 32) - buf = memcpy(buf, 32, message, 0) + copy(buf, digest1[32:]) + copy(buf[32:], message) messageDigest := sha512.Sum512(buf) var messageDigestReduced [32]byte @@ -62,9 +62,9 @@ func Sign(privateKey PrivateKey, message []byte) []byte { R.ToBytes(&encodedR) buf2 := make([]byte, 64+len(message)) - buf2 = memcpy(buf2, 0, encodedR, 0) - buf2 = memcpy(buf2, 32, privateKey, 32) - buf2 = memcpy(buf2, 64, message, 0) + copy(buf2, encodedR) + copy(buf2[32:], privateKey[32:]) + copy(buf2[64:], message) hramDigest := sha512.Sum512(buf2) var hramDigestReduced [32]byte @@ -75,15 +75,8 @@ func Sign(privateKey PrivateKey, message []byte) []byte { messageDigestReduced) var signature [SignatureSize]byte - signature = memcpy(signature, 0, encodedR, 0) - signature = memcpy(signature, 32, s, 0) + copy(signature, encodedR) + copy(signature[32:], s) return signature } - -func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte { - for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ { - dst[dstOfs+i] = src[srcOfs+i] - } - return dst -} diff --git a/pkg/crypto/hmac/sha1.mpcl b/pkg/crypto/hmac/sha1.mpcl index db5a9b4d..cfd851f6 100644 --- a/pkg/crypto/hmac/sha1.mpcl +++ b/pkg/crypto/hmac/sha1.mpcl @@ -21,8 +21,8 @@ func SumSHA1(data, key []byte) [sha1.Size]byte { var ipad [sha1.BlockSize]byte var opad [sha1.BlockSize]byte - ipad = memcpy(ipad, 0, key, 0) - opad = memcpy(opad, 0, key, 0) + copy(ipad, key) + copy(opad, key) for i := 0; i < len(ipad); i++ { ipad[i] ^= 0x36 @@ -32,14 +32,14 @@ func SumSHA1(data, key []byte) [sha1.Size]byte { } var idata [len(ipad) + len(data)]byte - idata = memcpy(idata, 0, ipad, 0) - idata = memcpy(idata, len(ipad), data, 0) + copy(idata, ipad) + copy(idata[len(ipad):], data) idigest := sha1.Sum(idata[:]) var odata [len(opad) + len(idigest)]byte - odata = memcpy(odata, 0, opad, 0) - odata = memcpy(odata, len(opad), idigest, 0) + copy(odata, opad) + copy(odata[len(opad):], idigest) return sha1.Sum(odata[:]) } diff --git a/pkg/crypto/hmac/sha256.mpcl b/pkg/crypto/hmac/sha256.mpcl index ad22a033..5d173b42 100644 --- a/pkg/crypto/hmac/sha256.mpcl +++ b/pkg/crypto/hmac/sha256.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2020-2021 Markku Rossi +// Copyright (c) 2020-2024 Markku Rossi // // All rights reserved. // @@ -21,8 +21,8 @@ func SumSHA256(data, key []byte) [sha256.Size]byte { var ipad [sha256.BlockSize]byte var opad [sha256.BlockSize]byte - ipad = memcpy(ipad, 0, key, 0) - opad = memcpy(opad, 0, key, 0) + copy(ipad, key) + copy(opad, key) for i := 0; i < len(ipad); i++ { ipad[i] ^= 0x36 @@ -32,21 +32,14 @@ func SumSHA256(data, key []byte) [sha256.Size]byte { } var idata [len(ipad) + len(data)]byte - idata = memcpy(idata, 0, ipad, 0) - idata = memcpy(idata, len(ipad), data, 0) + copy(idata, ipad) + copy(idata[len(ipad):], data) idigest := sha256.Sum256(idata[:]) var odata [len(opad) + len(idigest)]byte - odata = memcpy(odata, 0, opad, 0) - odata = memcpy(odata, len(opad), idigest, 0) + copy(odata, opad) + copy(odata[len(opad):], idigest) return sha256.Sum256(odata[:]) } - -func memcpy(dst []byte, dstOfs int, src []byte, srcOfs int) []byte { - for i := 0; srcOfs+i < len(src) && dstOfs+i < len(dst); i++ { - dst[dstOfs+i] = src[srcOfs+i] - } - return dst -} diff --git a/pkg/crypto/hmac/sha512.mpcl b/pkg/crypto/hmac/sha512.mpcl index e0b76967..4287d872 100644 --- a/pkg/crypto/hmac/sha512.mpcl +++ b/pkg/crypto/hmac/sha512.mpcl @@ -1,6 +1,6 @@ // -*- go -*- // -// Copyright (c) 2020-2021 Markku Rossi +// Copyright (c) 2020-2024 Markku Rossi // // All rights reserved. // @@ -21,8 +21,8 @@ func SumSHA512(data, key []byte) [sha512.Size]byte { var ipad [sha512.BlockSize]byte var opad [sha512.BlockSize]byte - ipad = memcpy(ipad, 0, key, 0) - opad = memcpy(opad, 0, key, 0) + copy(ipad, key) + copy(opad, key) for i := 0; i < len(ipad); i++ { ipad[i] ^= 0x36 @@ -32,14 +32,14 @@ func SumSHA512(data, key []byte) [sha512.Size]byte { } var idata [len(ipad) + len(data)]byte - idata = memcpy(idata, 0, ipad, 0) - idata = memcpy(idata, len(ipad), data, 0) + copy(idata, ipad) + copy(idata[len(ipad):], data) idigest := sha512.Sum512(idata[:]) var odata [len(opad) + len(idigest)]byte - odata = memcpy(odata, 0, opad, 0) - odata = memcpy(odata, len(opad), idigest, 0) + copy(odata, opad) + copy(odata[len(opad):], idigest) return sha512.Sum512(odata[:]) } diff --git a/testsuite/lang/copy_make.mpcl b/testsuite/lang/copy_make.mpcl new file mode 100644 index 00000000..a7f41ec0 --- /dev/null +++ b/testsuite/lang/copy_make.mpcl @@ -0,0 +1,17 @@ +// -*- go -*- + +package main + +// @Hex +// @LSB +// @Test 0x11223344 0xaabb = 0x11223344aa 0x11223344aa 5 +func main(g, e []byte) ([]byte, []byte, int) { + buf := make([]byte, 5) + n := copy(buf, g) + m := copy(buf[n:], e) + + buf2 := make([]byte, 5) + copy(buf2, buf) + + return buf, buf2, n + m +} diff --git a/testsuite/lang/slice.mpcl b/testsuite/lang/slice.mpcl deleted file mode 100644 index 8f5c103e..00000000 --- a/testsuite/lang/slice.mpcl +++ /dev/null @@ -1,9 +0,0 @@ -// -*- go -*- -// - -package main - -// @Test 4294967295 0 = 255 -func main(a, b uint64) uint { - return (a + b)[:8] -}