github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/internal/edwards25519/field/fe_alias_test.go (about) 1 // Copyright (c) 2019 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 field 6 7 import ( 8 "testing" 9 "testing/quick" 10 ) 11 12 func checkAliasingOneArg(f func(v, x *Element) *Element) func(v, x Element) bool { 13 return func(v, x Element) bool { 14 x1, v1 := x, x 15 16 // Calculate a reference f(x) without aliasing. 17 if out := f(&v, &x); out != &v && isInBounds(out) { 18 return false 19 } 20 21 // Test aliasing the argument and the receiver. 22 if out := f(&v1, &v1); out != &v1 || v1 != v { 23 return false 24 } 25 26 // Ensure the arguments was not modified. 27 return x == x1 28 } 29 } 30 31 func checkAliasingTwoArgs(f func(v, x, y *Element) *Element) func(v, x, y Element) bool { 32 return func(v, x, y Element) bool { 33 x1, y1, v1 := x, y, Element{} 34 35 // Calculate a reference f(x, y) without aliasing. 36 if out := f(&v, &x, &y); out != &v && isInBounds(out) { 37 return false 38 } 39 40 // Test aliasing the first argument and the receiver. 41 v1 = x 42 if out := f(&v1, &v1, &y); out != &v1 || v1 != v { 43 return false 44 } 45 // Test aliasing the second argument and the receiver. 46 v1 = y 47 if out := f(&v1, &x, &v1); out != &v1 || v1 != v { 48 return false 49 } 50 51 // Calculate a reference f(x, x) without aliasing. 52 if out := f(&v, &x, &x); out != &v { 53 return false 54 } 55 56 // Test aliasing the first argument and the receiver. 57 v1 = x 58 if out := f(&v1, &v1, &x); out != &v1 || v1 != v { 59 return false 60 } 61 // Test aliasing the second argument and the receiver. 62 v1 = x 63 if out := f(&v1, &x, &v1); out != &v1 || v1 != v { 64 return false 65 } 66 // Test aliasing both arguments and the receiver. 67 v1 = x 68 if out := f(&v1, &v1, &v1); out != &v1 || v1 != v { 69 return false 70 } 71 72 // Ensure the arguments were not modified. 73 return x == x1 && y == y1 74 } 75 } 76 77 // TestAliasing checks that receivers and arguments can alias each other without 78 // leading to incorrect results. That is, it ensures that it's safe to write 79 // 80 // v.Invert(v) 81 // 82 // or 83 // 84 // v.Add(v, v) 85 // 86 // without any of the inputs getting clobbered by the output being written. 87 func TestAliasing(t *testing.T) { 88 type target struct { 89 name string 90 oneArgF func(v, x *Element) *Element 91 twoArgsF func(v, x, y *Element) *Element 92 } 93 for _, tt := range []target{ 94 {name: "Absolute", oneArgF: (*Element).Absolute}, 95 {name: "Invert", oneArgF: (*Element).Invert}, 96 {name: "Negate", oneArgF: (*Element).Negate}, 97 {name: "Set", oneArgF: (*Element).Set}, 98 {name: "Square", oneArgF: (*Element).Square}, 99 {name: "Pow22523", oneArgF: (*Element).Pow22523}, 100 { 101 name: "Mult32", 102 oneArgF: func(v, x *Element) *Element { 103 return v.Mult32(x, 0xffffffff) 104 }, 105 }, 106 {name: "Multiply", twoArgsF: (*Element).Multiply}, 107 {name: "Add", twoArgsF: (*Element).Add}, 108 {name: "Subtract", twoArgsF: (*Element).Subtract}, 109 { 110 name: "SqrtRatio", 111 twoArgsF: func(v, x, y *Element) *Element { 112 r, _ := v.SqrtRatio(x, y) 113 return r 114 }, 115 }, 116 { 117 name: "Select0", 118 twoArgsF: func(v, x, y *Element) *Element { 119 return v.Select(x, y, 0) 120 }, 121 }, 122 { 123 name: "Select1", 124 twoArgsF: func(v, x, y *Element) *Element { 125 return v.Select(x, y, 1) 126 }, 127 }, 128 } { 129 var err error 130 switch { 131 case tt.oneArgF != nil: 132 err = quick.Check(checkAliasingOneArg(tt.oneArgF), &quick.Config{MaxCountScale: 1 << 8}) 133 case tt.twoArgsF != nil: 134 err = quick.Check(checkAliasingTwoArgs(tt.twoArgsF), &quick.Config{MaxCountScale: 1 << 8}) 135 } 136 if err != nil { 137 t.Errorf("%v: %v", tt.name, err) 138 } 139 } 140 }