github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/crypto/elliptic/p224_test.go (about) 1 // Copyright 2012 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 elliptic 6 7 import ( 8 "math/big" 9 "math/bits" 10 "math/rand" 11 "reflect" 12 "testing" 13 "testing/quick" 14 ) 15 16 var toFromBigTests = []string{ 17 "0", 18 "1", 19 "23", 20 "b70e0cb46bb4bf7f321390b94a03c1d356c01122343280d6105c1d21", 21 "706a46d476dcb76798e6046d89474788d164c18032d268fd10704fa6", 22 } 23 24 func p224AlternativeToBig(in *p224FieldElement) *big.Int { 25 ret := new(big.Int) 26 tmp := new(big.Int) 27 28 for i := len(in) - 1; i >= 0; i-- { 29 ret.Lsh(ret, 28) 30 tmp.SetInt64(int64(in[i])) 31 ret.Add(ret, tmp) 32 } 33 ret.Mod(ret, P224().Params().P) 34 return ret 35 } 36 37 func TestP224ToFromBig(t *testing.T) { 38 for i, test := range toFromBigTests { 39 n, _ := new(big.Int).SetString(test, 16) 40 var x p224FieldElement 41 p224FromBig(&x, n) 42 m := p224ToBig(&x) 43 if n.Cmp(m) != 0 { 44 t.Errorf("#%d: %x != %x", i, n, m) 45 } 46 q := p224AlternativeToBig(&x) 47 if n.Cmp(q) != 0 { 48 t.Errorf("#%d: %x != %x (alternative)", i, n, q) 49 } 50 } 51 } 52 53 // quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks) 54 // times. The default value of -quickchecks is 100. 55 var quickCheckConfig32 = &quick.Config{MaxCountScale: 32} 56 57 // weirdLimbs can be combined to generate a range of edge-case field elements. 58 var weirdLimbs = [...]uint32{ 59 0, 1, (1 << 29) - 1, 60 (1 << 12), (1 << 12) - 1, 61 (1 << 28), (1 << 28) - 1, 62 } 63 64 func generateLimb(rand *rand.Rand) uint32 { 65 const bottom29Bits = 0x1fffffff 66 n := rand.Intn(len(weirdLimbs) + 3) 67 switch n { 68 case len(weirdLimbs): 69 // Random value. 70 return uint32(rand.Int31n(1 << 29)) 71 case len(weirdLimbs) + 1: 72 // Sum of two values. 73 k := generateLimb(rand) + generateLimb(rand) 74 return k & bottom29Bits 75 case len(weirdLimbs) + 2: 76 // Difference of two values. 77 k := generateLimb(rand) - generateLimb(rand) 78 return k & bottom29Bits 79 default: 80 return weirdLimbs[n] 81 } 82 } 83 84 func (p224FieldElement) Generate(rand *rand.Rand, size int) reflect.Value { 85 return reflect.ValueOf(p224FieldElement{ 86 generateLimb(rand), 87 generateLimb(rand), 88 generateLimb(rand), 89 generateLimb(rand), 90 generateLimb(rand), 91 generateLimb(rand), 92 generateLimb(rand), 93 generateLimb(rand), 94 }) 95 } 96 97 func isInBounds(x *p224FieldElement) bool { 98 return bits.Len32(x[0]) <= 29 && 99 bits.Len32(x[1]) <= 29 && 100 bits.Len32(x[2]) <= 29 && 101 bits.Len32(x[3]) <= 29 && 102 bits.Len32(x[4]) <= 29 && 103 bits.Len32(x[5]) <= 29 && 104 bits.Len32(x[6]) <= 29 && 105 bits.Len32(x[7]) <= 29 106 } 107 108 func TestP224Mul(t *testing.T) { 109 mulMatchesBigInt := func(a, b, out p224FieldElement) bool { 110 var tmp p224LargeFieldElement 111 p224Mul(&out, &a, &b, &tmp) 112 113 exp := new(big.Int).Mul(p224AlternativeToBig(&a), p224AlternativeToBig(&b)) 114 exp.Mod(exp, P224().Params().P) 115 got := p224AlternativeToBig(&out) 116 if exp.Cmp(got) != 0 || !isInBounds(&out) { 117 t.Logf("a = %x", a) 118 t.Logf("b = %x", b) 119 t.Logf("p224Mul(a, b) = %x = %v", out, got) 120 t.Logf("a * b = %v", exp) 121 return false 122 } 123 124 return true 125 } 126 127 a := p224FieldElement{0xfffffff, 0xfffffff, 0xf00ffff, 0x20f, 0x0, 0x0, 0x0, 0x0} 128 b := p224FieldElement{1, 0, 0, 0, 0, 0, 0, 0} 129 if !mulMatchesBigInt(a, b, p224FieldElement{}) { 130 t.Fail() 131 } 132 133 if err := quick.Check(mulMatchesBigInt, quickCheckConfig32); err != nil { 134 t.Error(err) 135 } 136 } 137 138 func TestP224Square(t *testing.T) { 139 squareMatchesBigInt := func(a, out p224FieldElement) bool { 140 var tmp p224LargeFieldElement 141 p224Square(&out, &a, &tmp) 142 143 exp := p224AlternativeToBig(&a) 144 exp.Mul(exp, exp) 145 exp.Mod(exp, P224().Params().P) 146 got := p224AlternativeToBig(&out) 147 if exp.Cmp(got) != 0 || !isInBounds(&out) { 148 t.Logf("a = %x", a) 149 t.Logf("p224Square(a, b) = %x = %v", out, got) 150 t.Logf("a * a = %v", exp) 151 return false 152 } 153 154 return true 155 } 156 157 if err := quick.Check(squareMatchesBigInt, quickCheckConfig32); err != nil { 158 t.Error(err) 159 } 160 } 161 162 func TestP224Add(t *testing.T) { 163 addMatchesBigInt := func(a, b, out p224FieldElement) bool { 164 p224Add(&out, &a, &b) 165 166 exp := new(big.Int).Add(p224AlternativeToBig(&a), p224AlternativeToBig(&b)) 167 exp.Mod(exp, P224().Params().P) 168 got := p224AlternativeToBig(&out) 169 if exp.Cmp(got) != 0 { 170 t.Logf("a = %x", a) 171 t.Logf("b = %x", b) 172 t.Logf("p224Add(a, b) = %x = %v", out, got) 173 t.Logf("a + b = %v", exp) 174 return false 175 } 176 177 return true 178 } 179 180 if err := quick.Check(addMatchesBigInt, quickCheckConfig32); err != nil { 181 t.Error(err) 182 } 183 } 184 185 func TestP224Reduce(t *testing.T) { 186 reduceMatchesBigInt := func(a p224FieldElement) bool { 187 out := a 188 // TODO: generate higher values for functions like p224Reduce that are 189 // expected to work with higher input bounds. 190 p224Reduce(&out) 191 192 exp := p224AlternativeToBig(&a) 193 got := p224AlternativeToBig(&out) 194 if exp.Cmp(got) != 0 || !isInBounds(&out) { 195 t.Logf("a = %x = %v", a, exp) 196 t.Logf("p224Reduce(a) = %x = %v", out, got) 197 return false 198 } 199 200 return true 201 } 202 203 if err := quick.Check(reduceMatchesBigInt, quickCheckConfig32); err != nil { 204 t.Error(err) 205 } 206 } 207 208 func TestP224Contract(t *testing.T) { 209 contractMatchesBigInt := func(a, out p224FieldElement) bool { 210 p224Contract(&out, &a) 211 212 exp := p224AlternativeToBig(&a) 213 got := p224AlternativeToBig(&out) 214 if exp.Cmp(got) != 0 { 215 t.Logf("a = %x = %v", a, exp) 216 t.Logf("p224Contract(a) = %x = %v", out, got) 217 return false 218 } 219 220 // Check that out < P. 221 for i := range p224P { 222 k := 8 - i - 1 223 if out[k] > p224P[k] { 224 t.Logf("p224Contract(a) = %x", out) 225 return false 226 } 227 if out[k] < p224P[k] { 228 return true 229 } 230 } 231 t.Logf("p224Contract(a) = %x", out) 232 return false 233 } 234 235 if !contractMatchesBigInt(p224P, p224FieldElement{}) { 236 t.Error("p224Contract(p) is broken") 237 } 238 pMinus1 := p224FieldElement{0, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff} 239 if !contractMatchesBigInt(pMinus1, p224FieldElement{}) { 240 t.Error("p224Contract(p - 1) is broken") 241 } 242 // Check that we can handle input above p, but lowest limb zero. 243 a := p224FieldElement{0, 1, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff} 244 if !contractMatchesBigInt(a, p224FieldElement{}) { 245 t.Error("p224Contract(p + 2²⁸) is broken") 246 } 247 // Check that we can handle input above p, but lowest three limbs zero. 248 b := p224FieldElement{0, 0, 0, 0xffff001, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff} 249 if !contractMatchesBigInt(b, p224FieldElement{}) { 250 t.Error("p224Contract(p + 2⁸⁴) is broken") 251 } 252 253 if err := quick.Check(contractMatchesBigInt, quickCheckConfig32); err != nil { 254 t.Error(err) 255 } 256 } 257 258 func TestP224IsZero(t *testing.T) { 259 if got := p224IsZero(&p224FieldElement{}); got != 1 { 260 t.Errorf("p224IsZero(0) = %d, expected 1", got) 261 } 262 if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 { 263 t.Errorf("p224IsZero(p) = %d, expected 1", got) 264 } 265 if got := p224IsZero(&p224FieldElement{1}); got != 0 { 266 t.Errorf("p224IsZero(1) = %d, expected 0", got) 267 } 268 269 isZeroMatchesBigInt := func(a p224FieldElement) bool { 270 isZero := p224IsZero(&a) 271 272 big := p224AlternativeToBig(&a) 273 if big.Sign() == 0 && isZero != 1 { 274 return false 275 } 276 if big.Sign() != 0 && isZero != 0 { 277 return false 278 } 279 return true 280 } 281 282 if err := quick.Check(isZeroMatchesBigInt, quickCheckConfig32); err != nil { 283 t.Error(err) 284 } 285 } 286 287 func TestP224Invert(t *testing.T) { 288 var out p224FieldElement 289 290 p224Invert(&out, &p224FieldElement{}) 291 if got := p224IsZero(&out); got != 1 { 292 t.Errorf("p224Invert(0) = %x, expected 0", out) 293 } 294 295 p224Invert(&out, (*p224FieldElement)(&p224P)) 296 if got := p224IsZero(&out); got != 1 { 297 t.Errorf("p224Invert(p) = %x, expected 0", out) 298 } 299 300 p224Invert(&out, &p224FieldElement{1}) 301 p224Contract(&out, &out) 302 if out != (p224FieldElement{1}) { 303 t.Errorf("p224Invert(1) = %x, expected 1", out) 304 } 305 306 var tmp p224LargeFieldElement 307 a := p224FieldElement{1, 2, 3, 4, 5, 6, 7, 8} 308 p224Invert(&out, &a) 309 p224Mul(&out, &out, &a, &tmp) 310 p224Contract(&out, &out) 311 if out != (p224FieldElement{1}) { 312 t.Errorf("p224Invert(a) * a = %x, expected 1", out) 313 } 314 }