github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/crypto/crypto_test.go (about) 1 // Copyright 2014 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package crypto 18 19 import ( 20 "bytes" 21 "crypto/ecdsa" 22 "crypto/rand" 23 "encoding/hex" 24 "fmt" 25 "io/ioutil" 26 "math/big" 27 "os" 28 "testing" 29 30 "github.com/SmartMeshFoundation/Spectrum/crypto/secp256k1" 31 "github.com/SmartMeshFoundation/Spectrum/crypto/vrf" 32 33 "crypto/elliptic" 34 35 "github.com/SmartMeshFoundation/Spectrum/common" 36 ) 37 38 var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791" 39 var testPrivHex = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032" 40 41 // These tests are sanity checks. 42 // They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256 43 // and that the sha3 library uses keccak-f permutation. 44 func TestKeccak256Hash(t *testing.T) { 45 msg := []byte("abc") 46 exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") 47 checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp) 48 } 49 50 func TestToECDSAErrors(t *testing.T) { 51 if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil { 52 t.Fatal("HexToECDSA should've returned error") 53 } 54 if _, err := HexToECDSA("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); err == nil { 55 t.Fatal("HexToECDSA should've returned error") 56 } 57 } 58 59 func BenchmarkSha3(b *testing.B) { 60 a := []byte("hello world") 61 for i := 0; i < b.N; i++ { 62 Keccak256(a) 63 } 64 } 65 66 func TestVRFByExtra(t *testing.T) { 67 /* 68 23->24 : 78750960575072602031716003452811896949899840465614369727943970206889973630898 69 24->25 : 18412240434434283493026822705484548127888845974056244411367015130186730154773 70 */ 71 dataList := map[string]string{ 72 "25": `ae1b76d16042cc7215382e989c4f38ceab16c6c83ef321a71bf84c4f3e3fc7b24c683d54da82f628897d659512255276609b70d5fd859fba21e08cea8a0b0ce3b3cdc29d27aa32145a6dd638638f850a0fe37c6fe74f9eccd0b36d00b6063449045736447641f7598906e77178e92324aae9d0fdae197eae1b110b04422cab74cc373eb6b3a1ca4e5345582c96e7d2a8fac2a79e1dcb3aa0fa644ee13cb88b8651351130fac7a558fb6587b97df89dda04b88d992870523f5c98225e865211fe04017355a9e3a41a7d6394d76cb95217e745ab162070da228315843af8aea27e0d01`, 73 "26": `28b4f572ac63791e74e31371e07c4f6fb4c5af1701fe734300e0f31e34abab1580e89c3ac75f49fc03916ea656795583e38694a6aad6adf0b5ad241addea34701c698876087186861c146619369f1080a9d870876c89f7607317107d72a04e9304bb0fafcda8866ef2d60c68e9153e1b56b7a99c2cd72167a92ffbd126db1271529c83f2eacd80fcc5b678330566662f4ec7e5d08e68bc23eb83da0690ab7490aef0ad465fc69153b71575aed20ceb576e457bc54dee7216ab8eb5e429d6e44a182c2c5f9cafcb1705631f2087ccfc029361a4ac1c82f7c2a852d9e29d7014e00b00`, 74 } 75 for k, data := range dataList { 76 buf, _ := hex.DecodeString(data) 77 i := buf[:32] 78 n := new(big.Int).SetBytes(i) 79 t.Log(k, n) 80 } 81 82 } 83 84 func TestVRFF(t *testing.T) { 85 key, _ := HexToECDSA("0bcd616498bf7aa08be3aacf5a8e9396dce2977c7e475269c47aa869c1743009") 86 vrfPrv := vrf.PrivateKey{key} 87 vrfPub := vrf.PublicKey{&key.PublicKey} 88 msg, _ := hex.DecodeString("6dde11794aa31fb385b9d8d7ea1cfa03e5a0f389efb9cd90be388a342bdf8d7e") 89 i1, p1 := vrfPrv.Evaluate(msg) 90 i2, p2 := vrfPrv.Evaluate(msg) 91 t.Log(len(i1), len(p1), p1) 92 t.Log(len(i2), len(p2), p2) 93 v1, _ := vrfPub.ProofToHash(msg, p1) 94 v2, _ := vrfPub.ProofToHash(msg, p2) 95 t.Log(i1 == v1, v1) 96 t.Log(i2 == v2, v2) 97 for i := 0; i < 30000; i++ { 98 i3, p3 := vrfPrv.Evaluate(msg) 99 if len(i3) != 32 { 100 t.Log("XXX", len(i3), i) 101 } 102 if len(p3) != 129 { 103 t.Log("YYY", len(p3), i) 104 } 105 } 106 } 107 108 func TestVRF(t *testing.T) { 109 key, err := GenerateKey() 110 if err != nil { 111 t.Error(err) 112 return 113 } 114 k, err := vrf.NewVRFSigner(key) 115 if err != nil { 116 t.Error(err) 117 return 118 } 119 pk, err := vrf.NewVRFVerifier(&key.PublicKey) 120 if err != nil { 121 t.Error(err) 122 return 123 } 124 msg := []byte("data1") 125 index, proof := k.Evaluate(msg) 126 _index, _proof := k.Evaluate(msg) 127 index2, err := pk.ProofToHash(msg, proof) 128 129 if err != nil { 130 t.Error(err) 131 } 132 if index2 != index { 133 t.Error("index not equal") 134 } 135 136 t.Log(index) 137 t.Log(_index) 138 t.Log("=========") 139 t.Log(proof) 140 t.Log(_proof) 141 } 142 143 func TestVRF1(t *testing.T) { 144 //data := "89702163480656fb718d9a06d56f719fda0ab2361d42de308ef3589a0a71f8e11a11c9d38a6a0c8e58c6d3a64a5dbd9a914216dc997f48c186daa4d772e613136005baac9928765fc92db4b541b05e5ef1638c56594ef2af2d80c735feb169437e0d56aafd225566059da85922d1a2bea0ebd7da5b63d1e2d846109378a075d67d00" 145 msg := []byte("helloworld") 146 prv, _ := HexToECDSA("507fd083b5c5af7e645e77a3a3a82708f3af304164e02612ab4b1d5b36c627c6") 147 pub := &prv.PublicKey 148 np, _ := SimpleVRF2Bytes(prv, msg) 149 t.Log("vrfnp", len(np), np) 150 t.Log(hex.EncodeToString(np)) 151 err := SimpleVRFVerify(pub, msg, np) 152 t.Log("verify", err) 153 154 buf := elliptic.Marshal(pub.Curve, pub.X, pub.Y) 155 156 var signer common.Address 157 copy(signer[:], Keccak256(buf[1:])[12:]) 158 159 aa := PubkeyToAddress(*pub) 160 161 t.Log(signer.Hex()) 162 t.Log(aa.Hex()) 163 164 x, y := elliptic.Unmarshal(S256(), buf) 165 t.Log(x, pub.X) 166 t.Log(y, pub.Y) 167 168 pub2 := ecdsa.PublicKey{S256(), x, y} 169 t.Log(PubkeyToAddress(pub2).Hex()) 170 171 } 172 173 /* 174 私钥 : 0bcd616498bf7aa08be3aacf5a8e9396dce2977c7e475269c47aa869c1743009 175 原文 : 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c 176 177 签名结果 178 R : 0xa006360ed68f21443221354903f49dce733afaaeac3b35d420bb2154746c9592 179 S : 0x6f31ccfa10b449531fd0fff78db52cc02edaabd2c5e9a6abb8fc1cd6df26f442 180 V : 28 181 182 ------------------------- 183 r = sigHex[0:64] 184 s = sigHex[64:128] 185 v = sigHex[128:130] + 27 186 ------------------------- 187 */ 188 func TestSign2(t *testing.T) { 189 key, _ := HexToECDSA("0bcd616498bf7aa08be3aacf5a8e9396dce2977c7e475269c47aa869c1743009") 190 msg := Keccak256(common.HexToAddress("0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c").Bytes()) 191 192 sig, _ := Sign(msg, key) 193 sigHex := hex.EncodeToString(sig) 194 pubAddr := PubkeyToAddress(key.PublicKey) 195 t.Log("addr =", pubAddr.Hex()) 196 t.Log("msg =", hex.EncodeToString(msg)) 197 t.Log("Sign =", sigHex) 198 r, _ := hex.DecodeString(sigHex[:64]) 199 buff := []byte(r) 200 fmt.Println("llllll=", len(buff), len(sig)) 201 fmt.Println(r) 202 203 var r32 [32]byte 204 copy(r32[:], r) 205 fmt.Println(len(r32), "r32=", r32) 206 207 fmt.Println(sig[:32]) 208 R := "0x" + sigHex[:64] 209 S := "0x" + sigHex[64:128] 210 V := 27 211 switch sigHex[128:] { 212 case "01": 213 V = 28 214 } 215 t.Log("-----------------------------------------") 216 t.Log("R:", R) 217 t.Log("S:", S) 218 t.Log("V:", V) 219 220 } 221 222 func TestSign(t *testing.T) { 223 key, _ := HexToECDSA(testPrivHex) 224 addr := common.HexToAddress(testAddrHex) 225 226 msg := Keccak256([]byte("foobar")) 227 sig, err := Sign(msg, key) 228 t.Log("Sign =", sig) 229 t.Log("Sign.len =", len(sig)) 230 t.Log("Sign.hex =", hex.EncodeToString(sig)) 231 if err != nil { 232 t.Errorf("Sign error: %s", err) 233 } 234 recoveredPub, err := Ecrecover(msg, sig) 235 if err != nil { 236 t.Errorf("ECRecover error: %s", err) 237 } 238 pubKey := ToECDSAPub(recoveredPub) 239 recoveredAddr := PubkeyToAddress(*pubKey) 240 if addr != recoveredAddr { 241 t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr) 242 } 243 244 // should be equal to SigToPub 245 recoveredPub2, err := SigToPub(msg, sig) 246 if err != nil { 247 t.Errorf("ECRecover error: %s", err) 248 } 249 recoveredAddr2 := PubkeyToAddress(*recoveredPub2) 250 if addr != recoveredAddr2 { 251 t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr2) 252 } 253 } 254 255 func TestInvalidSign(t *testing.T) { 256 if _, err := Sign(make([]byte, 1), nil); err == nil { 257 t.Errorf("expected sign with hash 1 byte to error") 258 } 259 if _, err := Sign(make([]byte, 33), nil); err == nil { 260 t.Errorf("expected sign with hash 33 byte to error") 261 } 262 } 263 264 func TestNewContractAddress(t *testing.T) { 265 key, _ := HexToECDSA(testPrivHex) 266 addr := common.HexToAddress(testAddrHex) 267 genAddr := PubkeyToAddress(key.PublicKey) 268 // sanity check before using addr to create contract address 269 checkAddr(t, genAddr, addr) 270 271 caddr0 := CreateAddress(addr, 0) 272 caddr1 := CreateAddress(addr, 1) 273 caddr2 := CreateAddress(addr, 2) 274 checkAddr(t, common.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), caddr0) 275 checkAddr(t, common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"), caddr1) 276 checkAddr(t, common.HexToAddress("c9ddedf451bc62ce88bf9292afb13df35b670699"), caddr2) 277 } 278 279 func TestLoadECDSAFile(t *testing.T) { 280 keyBytes := common.FromHex(testPrivHex) 281 fileName0 := "test_key0" 282 fileName1 := "test_key1" 283 checkKey := func(k *ecdsa.PrivateKey) { 284 checkAddr(t, PubkeyToAddress(k.PublicKey), common.HexToAddress(testAddrHex)) 285 loadedKeyBytes := FromECDSA(k) 286 if !bytes.Equal(loadedKeyBytes, keyBytes) { 287 t.Fatalf("private key mismatch: want: %x have: %x", keyBytes, loadedKeyBytes) 288 } 289 } 290 291 ioutil.WriteFile(fileName0, []byte(testPrivHex), 0600) 292 defer os.Remove(fileName0) 293 294 key0, err := LoadECDSA(fileName0) 295 if err != nil { 296 t.Fatal(err) 297 } 298 checkKey(key0) 299 300 // again, this time with SaveECDSA instead of manual save: 301 err = SaveECDSA(fileName1, key0) 302 if err != nil { 303 t.Fatal(err) 304 } 305 defer os.Remove(fileName1) 306 307 key1, err := LoadECDSA(fileName1) 308 if err != nil { 309 t.Fatal(err) 310 } 311 checkKey(key1) 312 } 313 314 func TestValidateSignatureValues(t *testing.T) { 315 check := func(expected bool, v byte, r, s *big.Int) { 316 if ValidateSignatureValues(v, r, s, false) != expected { 317 t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected) 318 } 319 } 320 minusOne := big.NewInt(-1) 321 one := common.Big1 322 zero := common.Big0 323 secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1) 324 325 // correct v,r,s 326 check(true, 0, one, one) 327 check(true, 1, one, one) 328 // incorrect v, correct r,s, 329 check(false, 2, one, one) 330 check(false, 3, one, one) 331 332 // incorrect v, combinations of incorrect/correct r,s at lower limit 333 check(false, 2, zero, zero) 334 check(false, 2, zero, one) 335 check(false, 2, one, zero) 336 check(false, 2, one, one) 337 338 // correct v for any combination of incorrect r,s 339 check(false, 0, zero, zero) 340 check(false, 0, zero, one) 341 check(false, 0, one, zero) 342 343 check(false, 1, zero, zero) 344 check(false, 1, zero, one) 345 check(false, 1, one, zero) 346 347 // correct sig with max r,s 348 check(true, 0, secp256k1nMinus1, secp256k1nMinus1) 349 // correct v, combinations of incorrect r,s at upper limit 350 check(false, 0, secp256k1_N, secp256k1nMinus1) 351 check(false, 0, secp256k1nMinus1, secp256k1_N) 352 check(false, 0, secp256k1_N, secp256k1_N) 353 354 // current callers ensures r,s cannot be negative, but let's test for that too 355 // as crypto package could be used stand-alone 356 check(false, 0, minusOne, one) 357 check(false, 0, one, minusOne) 358 } 359 360 func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) { 361 sum := f(msg) 362 if !bytes.Equal(exp, sum) { 363 t.Fatalf("hash %s mismatch: want: %x have: %x", name, exp, sum) 364 } 365 } 366 367 func checkAddr(t *testing.T, addr0, addr1 common.Address) { 368 if addr0 != addr1 { 369 t.Fatalf("address mismatch: want: %x have: %x", addr0, addr1) 370 } 371 } 372 373 // test to help Python team with integration of libsecp256k1 374 // skip but keep it after they are done 375 func TestPythonIntegration(t *testing.T) { 376 kh := "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032" 377 k0, _ := HexToECDSA(kh) 378 379 msg0 := Keccak256([]byte("foo")) 380 sig0, _ := Sign(msg0, k0) 381 382 msg1 := common.FromHex("00000000000000000000000000000000") 383 sig1, _ := Sign(msg0, k0) 384 385 t.Logf("msg: %x, privkey: %s sig: %x\n", msg0, kh, sig0) 386 t.Logf("msg: %x, privkey: %s sig: %x\n", msg1, kh, sig1) 387 } 388 389 func TestToECDSA(t *testing.T) { 390 target := "0adec74681c34173416ae564849e53e52034156e238084948b53cd1f7a753d6cc90763b5024f26998ee192d9662232d4c68abd588347626c2e8cd95e5c1ca38b" 391 nodekey := "b07f62f843adf1622811a79945944748fe5e59174d1ceffd14ca90a35c5813a7" 392 k, _ := hex.DecodeString(nodekey) 393 prv, _ := ToECDSA(k) 394 // TODO 将一个公钥变成一个 nodeid 395 pub := prv.PublicKey 396 // 变成一个 Address 397 address := PubkeyToAddress(pub) 398 t.Log("address =", address.Hex()) 399 400 pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) 401 nodeid := pbytes[1:] 402 t.Log("---------------") 403 t.Log(target) 404 t.Log(hex.EncodeToString(nodeid)) 405 t.Logf("%x\n", nodeid) 406 t.Log(hex.EncodeToString(nodeid) == target) 407 } 408 409 func TestFromECDSA(t *testing.T) { 410 prv, _ := GenerateKey() 411 buf := FromECDSA(prv) 412 s := hex.EncodeToString(buf) 413 t.Log("key", s) 414 t.Log(PubkeyToAddress(prv.PublicKey).Hex()) 415 //0xd91c07c6be04111aecc721e57e11a8a0b1c73fc1 416 } 417 418 func TestForPOCDepositArgs(t *testing.T) { 419 prvkey1, _ := HexToECDSA("543e9d0ddcd02b4bbdb2cecd402da99e9532fface57d8ea74e833c5d413f2daa") 420 prvkey2, _ := HexToECDSA("9d7b3b8155ea429cb49cdc556aa7b3367feb91ccf51eb1e9c7e2bac67d939f03") 421 422 keys := []*ecdsa.PrivateKey{prvkey1, prvkey2} 423 424 msg := Keccak256(common.HexToAddress("0xbf1736a65f8beadd71b321be585fd883503fdeaa").Bytes()) 425 426 for _, key := range keys { 427 t.Log("========================================") 428 sig, _ := Sign(msg, key) 429 sigHex := hex.EncodeToString(sig) 430 pubAddr := PubkeyToAddress(key.PublicKey) 431 t.Log("msg =", hex.EncodeToString(msg)) 432 t.Log("Sign =", sigHex) 433 r, _ := hex.DecodeString(sigHex[:64]) 434 435 var r32 [32]byte 436 copy(r32[:], r) 437 fmt.Println(len(r32), "r32=", r32) 438 439 fmt.Println(sig[:32]) 440 R := "0x" + sigHex[:64] 441 S := "0x" + sigHex[64:128] 442 V := 27 443 switch sigHex[128:] { 444 case "01": 445 V = 28 446 } 447 t.Log("-----------------------------------------") 448 t.Log("addr:", pubAddr.Hex()) 449 t.Log("R:", R) 450 t.Log("S:", S) 451 t.Log("V:", V) 452 } 453 454 } 455 456 func TestVRFForS256Fenbu(t *testing.T) { 457 if testing.Short() { 458 return 459 } 460 key, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) 461 if err != nil { 462 t.Error(err) 463 return 464 } 465 fmt.Printf("key=%s\n", hex.EncodeToString(FromECDSA(key))) 466 var n = 380 467 var batch = 10000000 468 var k100 []*ecdsa.PrivateKey 469 for i := 0; i < n; i++ { 470 k, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) 471 if err != nil { 472 t.Error(err) 473 return 474 } 475 fmt.Printf("k%d=%s\n", i, hex.EncodeToString(FromECDSA(k))) 476 k100 = append(k100, k) 477 } 478 m := make(map[int]int) 479 var lastVrf []byte 480 for i := 0; i < batch; i++ { 481 var tk *ecdsa.PrivateKey 482 if i%17 == 0 || len(lastVrf) == 0 { 483 tk = key 484 } else { 485 num := new(big.Int).SetBytes(lastVrf) 486 num = num.Mod(num, big.NewInt(int64(n))) 487 tk = k100[num.Int64()] 488 m[int(num.Int64())] = m[int(num.Int64())] + 1 489 } 490 msg := append(big.NewInt(int64(i-1)).Bytes(), lastVrf...) 491 vrfnp, err := SimpleVRF2Bytes(tk, msg) 492 if err != nil { 493 t.Error(err) 494 return 495 } 496 lastVrf = vrfnp 497 } 498 var avg int 499 for k, v := range m { 500 avg += v 501 fmt.Printf("%d,%d\n", k, v) 502 } 503 fmt.Printf("total=%d", avg) 504 fmt.Printf("avg=%d", avg/n) 505 } 506 507 func TestVRFForS256Fenbu2(t *testing.T) { 508 if testing.Short() { 509 return 510 } 511 key, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) 512 if err != nil { 513 t.Error(err) 514 return 515 } 516 fmt.Printf("key=%s\n", hex.EncodeToString(FromECDSA(key))) 517 var n = 380 518 var batch = 1000000 519 var k100 []*ecdsa.PrivateKey 520 for i := 0; i < n; i++ { 521 k, err := ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) 522 if err != nil { 523 t.Error(err) 524 return 525 } 526 fmt.Printf("k%d=%s\n", i, hex.EncodeToString(FromECDSA(k))) 527 k100 = append(k100, k) 528 } 529 var signers [17]*ecdsa.PrivateKey 530 var nextRoundSigners [17]*ecdsa.PrivateKey 531 var emptySigners [17]*ecdsa.PrivateKey 532 signers[0] = key 533 copy(signers[1:17], k100[0:16]) 534 copy(nextRoundSigners[:], signers[:]) 535 find := func(num *big.Int) *ecdsa.PrivateKey { 536 num = num.Mod(num, big.NewInt(int64(n))) 537 k := num.Int64() 538 var ck *ecdsa.PrivateKey 539 for { 540 nextRound: 541 ck = k100[k] 542 for i := 0; i < 17; i++ { 543 if signers[i] == ck { 544 k++ 545 k = k % int64(n) 546 goto nextRound 547 } 548 } 549 for i := 0; i < 17; i++ { 550 if nextRoundSigners[i] == ck { 551 k++ 552 k = k % int64(n) 553 goto nextRound 554 } 555 } 556 break //没有和已选择的冲突 557 } 558 return ck 559 } 560 m := make(map[int]int) 561 var lastVrf []byte 562 for i := 0; i < batch; i++ { 563 var tk *ecdsa.PrivateKey 564 if i%17 == 0 || len(lastVrf) == 0 { 565 copy(signers[:], nextRoundSigners[:]) 566 copy(nextRoundSigners[:], emptySigners[:]) 567 tk = signers[0] 568 nextRoundSigners[0] = tk //第0个不变 569 } else { 570 num := new(big.Int).SetBytes(lastVrf) 571 tk = find(num) 572 m[int(num.Int64())] = m[int(num.Int64())] + 1 573 } 574 msg := append(big.NewInt(int64(i-1)).Bytes(), lastVrf...) 575 vrfnp, err := SimpleVRF2Bytes(tk, msg) 576 if err != nil { 577 t.Error(err) 578 return 579 } 580 lastVrf = vrfnp 581 } 582 var avg int 583 for k, v := range m { 584 avg += v 585 fmt.Printf("%d,%d\n", k, v) 586 } 587 fmt.Printf("total=%d", avg) 588 fmt.Printf("avg=%d", avg/n) 589 }