github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/crypto/internal/nistec/nistec_test.go (about) 1 // Copyright 2021 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 nistec_test 6 7 import ( 8 "bytes" 9 "crypto/elliptic" 10 "crypto/internal/nistec" 11 "internal/testenv" 12 "math/big" 13 "math/rand" 14 "testing" 15 ) 16 17 func TestAllocations(t *testing.T) { 18 testenv.SkipIfOptimizationOff(t) 19 20 t.Run("P224", func(t *testing.T) { 21 if allocs := testing.AllocsPerRun(100, func() { 22 p := nistec.NewP224Point().SetGenerator() 23 scalar := make([]byte, 28) 24 rand.Read(scalar) 25 p.ScalarBaseMult(scalar) 26 p.ScalarMult(p, scalar) 27 out := p.Bytes() 28 if _, err := nistec.NewP224Point().SetBytes(out); err != nil { 29 t.Fatal(err) 30 } 31 out = p.BytesCompressed() 32 if _, err := p.SetBytes(out); err != nil { 33 t.Fatal(err) 34 } 35 }); allocs > 0 { 36 t.Errorf("expected zero allocations, got %0.1f", allocs) 37 } 38 }) 39 t.Run("P256", func(t *testing.T) { 40 if allocs := testing.AllocsPerRun(100, func() { 41 p := nistec.NewP256Point().SetGenerator() 42 scalar := make([]byte, 32) 43 rand.Read(scalar) 44 p.ScalarBaseMult(scalar) 45 p.ScalarMult(p, scalar) 46 out := p.Bytes() 47 if _, err := nistec.NewP256Point().SetBytes(out); err != nil { 48 t.Fatal(err) 49 } 50 out = p.BytesCompressed() 51 if _, err := p.SetBytes(out); err != nil { 52 t.Fatal(err) 53 } 54 }); allocs > 0 { 55 t.Errorf("expected zero allocations, got %0.1f", allocs) 56 } 57 }) 58 t.Run("P384", func(t *testing.T) { 59 if allocs := testing.AllocsPerRun(100, func() { 60 p := nistec.NewP384Point().SetGenerator() 61 scalar := make([]byte, 48) 62 rand.Read(scalar) 63 p.ScalarBaseMult(scalar) 64 p.ScalarMult(p, scalar) 65 out := p.Bytes() 66 if _, err := nistec.NewP384Point().SetBytes(out); err != nil { 67 t.Fatal(err) 68 } 69 out = p.BytesCompressed() 70 if _, err := p.SetBytes(out); err != nil { 71 t.Fatal(err) 72 } 73 }); allocs > 0 { 74 t.Errorf("expected zero allocations, got %0.1f", allocs) 75 } 76 }) 77 t.Run("P521", func(t *testing.T) { 78 if allocs := testing.AllocsPerRun(100, func() { 79 p := nistec.NewP521Point().SetGenerator() 80 scalar := make([]byte, 66) 81 rand.Read(scalar) 82 p.ScalarBaseMult(scalar) 83 p.ScalarMult(p, scalar) 84 out := p.Bytes() 85 if _, err := nistec.NewP521Point().SetBytes(out); err != nil { 86 t.Fatal(err) 87 } 88 out = p.BytesCompressed() 89 if _, err := p.SetBytes(out); err != nil { 90 t.Fatal(err) 91 } 92 }); allocs > 0 { 93 t.Errorf("expected zero allocations, got %0.1f", allocs) 94 } 95 }) 96 } 97 98 type nistPoint[T any] interface { 99 Bytes() []byte 100 SetGenerator() T 101 SetBytes([]byte) (T, error) 102 Add(T, T) T 103 Double(T) T 104 ScalarMult(T, []byte) (T, error) 105 ScalarBaseMult([]byte) (T, error) 106 } 107 108 func TestEquivalents(t *testing.T) { 109 t.Run("P224", func(t *testing.T) { 110 testEquivalents(t, nistec.NewP224Point, elliptic.P224()) 111 }) 112 t.Run("P256", func(t *testing.T) { 113 testEquivalents(t, nistec.NewP256Point, elliptic.P256()) 114 }) 115 t.Run("P384", func(t *testing.T) { 116 testEquivalents(t, nistec.NewP384Point, elliptic.P384()) 117 }) 118 t.Run("P521", func(t *testing.T) { 119 testEquivalents(t, nistec.NewP521Point, elliptic.P521()) 120 }) 121 } 122 123 func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) { 124 p := newPoint().SetGenerator() 125 126 elementSize := (c.Params().BitSize + 7) / 8 127 two := make([]byte, elementSize) 128 two[len(two)-1] = 2 129 nPlusTwo := make([]byte, elementSize) 130 new(big.Int).Add(c.Params().N, big.NewInt(2)).FillBytes(nPlusTwo) 131 132 p1 := newPoint().Double(p) 133 p2 := newPoint().Add(p, p) 134 p3, err := newPoint().ScalarMult(p, two) 135 if err != nil { 136 t.Fatal(err) 137 } 138 p4, err := newPoint().ScalarBaseMult(two) 139 if err != nil { 140 t.Fatal(err) 141 } 142 p5, err := newPoint().ScalarMult(p, nPlusTwo) 143 if err != nil { 144 t.Fatal(err) 145 } 146 p6, err := newPoint().ScalarBaseMult(nPlusTwo) 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 if !bytes.Equal(p1.Bytes(), p2.Bytes()) { 152 t.Error("P+P != 2*P") 153 } 154 if !bytes.Equal(p1.Bytes(), p3.Bytes()) { 155 t.Error("P+P != [2]P") 156 } 157 if !bytes.Equal(p1.Bytes(), p4.Bytes()) { 158 t.Error("G+G != [2]G") 159 } 160 if !bytes.Equal(p1.Bytes(), p5.Bytes()) { 161 t.Error("P+P != [N+2]P") 162 } 163 if !bytes.Equal(p1.Bytes(), p6.Bytes()) { 164 t.Error("G+G != [N+2]G") 165 } 166 } 167 168 func BenchmarkScalarMult(b *testing.B) { 169 b.Run("P224", func(b *testing.B) { 170 benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28) 171 }) 172 b.Run("P256", func(b *testing.B) { 173 benchmarkScalarMult(b, nistec.NewP256Point().SetGenerator(), 32) 174 }) 175 b.Run("P384", func(b *testing.B) { 176 benchmarkScalarMult(b, nistec.NewP384Point().SetGenerator(), 48) 177 }) 178 b.Run("P521", func(b *testing.B) { 179 benchmarkScalarMult(b, nistec.NewP521Point().SetGenerator(), 66) 180 }) 181 } 182 183 func benchmarkScalarMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) { 184 scalar := make([]byte, scalarSize) 185 rand.Read(scalar) 186 b.ReportAllocs() 187 b.ResetTimer() 188 for i := 0; i < b.N; i++ { 189 p.ScalarMult(p, scalar) 190 } 191 } 192 193 func BenchmarkScalarBaseMult(b *testing.B) { 194 b.Run("P224", func(b *testing.B) { 195 benchmarkScalarBaseMult(b, nistec.NewP224Point().SetGenerator(), 28) 196 }) 197 b.Run("P256", func(b *testing.B) { 198 benchmarkScalarBaseMult(b, nistec.NewP256Point().SetGenerator(), 32) 199 }) 200 b.Run("P384", func(b *testing.B) { 201 benchmarkScalarBaseMult(b, nistec.NewP384Point().SetGenerator(), 48) 202 }) 203 b.Run("P521", func(b *testing.B) { 204 benchmarkScalarBaseMult(b, nistec.NewP521Point().SetGenerator(), 66) 205 }) 206 } 207 208 func benchmarkScalarBaseMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) { 209 scalar := make([]byte, scalarSize) 210 rand.Read(scalar) 211 b.ReportAllocs() 212 b.ResetTimer() 213 for i := 0; i < b.N; i++ { 214 p.ScalarBaseMult(scalar) 215 } 216 }