91d75e89 by slene

add readme for captcha, and enhanced performance

1 parent 3e400412
1 # Captcha
2
3 an example for use captcha
4
5 ```
6 package controllers
7
8 import (
9 "github.com/astaxie/beego"
10 "github.com/astaxie/beego/cache"
11 "github.com/astaxie/beego/utils/captcha"
12 )
13
14 var cpt *captcha.Captcha
15
16 func init() {
17 // use beego cache system store the captcha data
18 store := cache.NewMemoryCache()
19 cpt = captcha.NewWithFilter("/captcha/", store)
20 }
21
22 type MainController struct {
23 beego.Controller
24 }
25
26 func (this *MainController) Get() {
27 this.TplNames = "index.tpl"
28 }
29
30 func (this *MainController) Post() {
31 this.TplNames = "index.tpl"
32
33 this.Data["Success"] = cpt.VerifyReq(this.Ctx.Request)
34 }
35 ```
36
37 template usage
38
39 ```
40 {{.Success}}
41 <form action="/" method="post">
42 {{create_captcha}}
43 <input name="captcha" type="text">
44 </form>
45 ```
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
12 // var cpt *captcha.Captcha 12 // var cpt *captcha.Captcha
13 // 13 //
14 // func init() { 14 // func init() {
15 // // use beego cache system store the captcha data
15 // store := cache.NewMemoryCache() 16 // store := cache.NewMemoryCache()
16 // cpt = captcha.NewWithFilter("/captcha/", store) 17 // cpt = captcha.NewWithFilter("/captcha/", store)
17 // } 18 // }
......
...@@ -8,8 +8,6 @@ import ( ...@@ -8,8 +8,6 @@ import (
8 "image/png" 8 "image/png"
9 "io" 9 "io"
10 "math" 10 "math"
11 "math/rand"
12 "time"
13 ) 11 )
14 12
15 const ( 13 const (
...@@ -236,26 +234,21 @@ type Image struct { ...@@ -236,26 +234,21 @@ type Image struct {
236 dotSize int 234 dotSize int
237 } 235 }
238 236
239 func getrand() *rand.Rand { 237 var prng = &siprng{}
240 return rand.New(rand.NewSource(time.Now().UnixNano()))
241 }
242 238
243 func randIntn(max int) int { 239 // randIntn returns a pseudorandom non-negative int in range [0, n).
244 if max <= 0 { 240 func randIntn(n int) int {
245 return 0 241 return prng.Intn(n)
246 }
247 return getrand().Intn(max)
248 } 242 }
249 243
250 func randInt(min, max int) int { 244 // randInt returns a pseudorandom int in range [from, to].
251 if max-min <= 0 { 245 func randInt(from, to int) int {
252 return 0 246 return prng.Intn(to+1-from) + from
253 }
254 return getrand().Intn(max-min) + min
255 } 247 }
256 248
257 func randFloat(min, max float64) float64 { 249 // randFloat returns a pseudorandom float64 in range [from, to].
258 return (max-min)*getrand().Float64() + min 250 func randFloat(from, to float64) float64 {
251 return (to-from)*prng.Float64() + from
259 } 252 }
260 253
261 func randomPalette() color.Palette { 254 func randomPalette() color.Palette {
......
1 // modifiy and integrated to Beego from https://github.com/dchest/captcha
2 package captcha
3
4 import (
5 "crypto/rand"
6 "encoding/binary"
7 "io"
8 "sync"
9 )
10
11 // siprng is PRNG based on SipHash-2-4.
12 type siprng struct {
13 mu sync.Mutex
14 k0, k1, ctr uint64
15 }
16
17 // siphash implements SipHash-2-4, accepting a uint64 as a message.
18 func siphash(k0, k1, m uint64) uint64 {
19 // Initialization.
20 v0 := k0 ^ 0x736f6d6570736575
21 v1 := k1 ^ 0x646f72616e646f6d
22 v2 := k0 ^ 0x6c7967656e657261
23 v3 := k1 ^ 0x7465646279746573
24 t := uint64(8) << 56
25
26 // Compression.
27 v3 ^= m
28
29 // Round 1.
30 v0 += v1
31 v1 = v1<<13 | v1>>(64-13)
32 v1 ^= v0
33 v0 = v0<<32 | v0>>(64-32)
34
35 v2 += v3
36 v3 = v3<<16 | v3>>(64-16)
37 v3 ^= v2
38
39 v0 += v3
40 v3 = v3<<21 | v3>>(64-21)
41 v3 ^= v0
42
43 v2 += v1
44 v1 = v1<<17 | v1>>(64-17)
45 v1 ^= v2
46 v2 = v2<<32 | v2>>(64-32)
47
48 // Round 2.
49 v0 += v1
50 v1 = v1<<13 | v1>>(64-13)
51 v1 ^= v0
52 v0 = v0<<32 | v0>>(64-32)
53
54 v2 += v3
55 v3 = v3<<16 | v3>>(64-16)
56 v3 ^= v2
57
58 v0 += v3
59 v3 = v3<<21 | v3>>(64-21)
60 v3 ^= v0
61
62 v2 += v1
63 v1 = v1<<17 | v1>>(64-17)
64 v1 ^= v2
65 v2 = v2<<32 | v2>>(64-32)
66
67 v0 ^= m
68
69 // Compress last block.
70 v3 ^= t
71
72 // Round 1.
73 v0 += v1
74 v1 = v1<<13 | v1>>(64-13)
75 v1 ^= v0
76 v0 = v0<<32 | v0>>(64-32)
77
78 v2 += v3
79 v3 = v3<<16 | v3>>(64-16)
80 v3 ^= v2
81
82 v0 += v3
83 v3 = v3<<21 | v3>>(64-21)
84 v3 ^= v0
85
86 v2 += v1
87 v1 = v1<<17 | v1>>(64-17)
88 v1 ^= v2
89 v2 = v2<<32 | v2>>(64-32)
90
91 // Round 2.
92 v0 += v1
93 v1 = v1<<13 | v1>>(64-13)
94 v1 ^= v0
95 v0 = v0<<32 | v0>>(64-32)
96
97 v2 += v3
98 v3 = v3<<16 | v3>>(64-16)
99 v3 ^= v2
100
101 v0 += v3
102 v3 = v3<<21 | v3>>(64-21)
103 v3 ^= v0
104
105 v2 += v1
106 v1 = v1<<17 | v1>>(64-17)
107 v1 ^= v2
108 v2 = v2<<32 | v2>>(64-32)
109
110 v0 ^= t
111
112 // Finalization.
113 v2 ^= 0xff
114
115 // Round 1.
116 v0 += v1
117 v1 = v1<<13 | v1>>(64-13)
118 v1 ^= v0
119 v0 = v0<<32 | v0>>(64-32)
120
121 v2 += v3
122 v3 = v3<<16 | v3>>(64-16)
123 v3 ^= v2
124
125 v0 += v3
126 v3 = v3<<21 | v3>>(64-21)
127 v3 ^= v0
128
129 v2 += v1
130 v1 = v1<<17 | v1>>(64-17)
131 v1 ^= v2
132 v2 = v2<<32 | v2>>(64-32)
133
134 // Round 2.
135 v0 += v1
136 v1 = v1<<13 | v1>>(64-13)
137 v1 ^= v0
138 v0 = v0<<32 | v0>>(64-32)
139
140 v2 += v3
141 v3 = v3<<16 | v3>>(64-16)
142 v3 ^= v2
143
144 v0 += v3
145 v3 = v3<<21 | v3>>(64-21)
146 v3 ^= v0
147
148 v2 += v1
149 v1 = v1<<17 | v1>>(64-17)
150 v1 ^= v2
151 v2 = v2<<32 | v2>>(64-32)
152
153 // Round 3.
154 v0 += v1
155 v1 = v1<<13 | v1>>(64-13)
156 v1 ^= v0
157 v0 = v0<<32 | v0>>(64-32)
158
159 v2 += v3
160 v3 = v3<<16 | v3>>(64-16)
161 v3 ^= v2
162
163 v0 += v3
164 v3 = v3<<21 | v3>>(64-21)
165 v3 ^= v0
166
167 v2 += v1
168 v1 = v1<<17 | v1>>(64-17)
169 v1 ^= v2
170 v2 = v2<<32 | v2>>(64-32)
171
172 // Round 4.
173 v0 += v1
174 v1 = v1<<13 | v1>>(64-13)
175 v1 ^= v0
176 v0 = v0<<32 | v0>>(64-32)
177
178 v2 += v3
179 v3 = v3<<16 | v3>>(64-16)
180 v3 ^= v2
181
182 v0 += v3
183 v3 = v3<<21 | v3>>(64-21)
184 v3 ^= v0
185
186 v2 += v1
187 v1 = v1<<17 | v1>>(64-17)
188 v1 ^= v2
189 v2 = v2<<32 | v2>>(64-32)
190
191 return v0 ^ v1 ^ v2 ^ v3
192 }
193
194 // rekey sets a new PRNG key, which is read from crypto/rand.
195 func (p *siprng) rekey() {
196 var k [16]byte
197 if _, err := io.ReadFull(rand.Reader, k[:]); err != nil {
198 panic(err.Error())
199 }
200 p.k0 = binary.LittleEndian.Uint64(k[0:8])
201 p.k1 = binary.LittleEndian.Uint64(k[8:16])
202 p.ctr = 1
203 }
204
205 // Uint64 returns a new pseudorandom uint64.
206 // It rekeys PRNG on the first call and every 64 MB of generated data.
207 func (p *siprng) Uint64() uint64 {
208 p.mu.Lock()
209 if p.ctr == 0 || p.ctr > 8*1024*1024 {
210 p.rekey()
211 }
212 v := siphash(p.k0, p.k1, p.ctr)
213 p.ctr++
214 p.mu.Unlock()
215 return v
216 }
217
218 func (p *siprng) Int63() int64 {
219 return int64(p.Uint64() & 0x7fffffffffffffff)
220 }
221
222 func (p *siprng) Uint32() uint32 {
223 return uint32(p.Uint64())
224 }
225
226 func (p *siprng) Int31() int32 {
227 return int32(p.Uint32() & 0x7fffffff)
228 }
229
230 func (p *siprng) Intn(n int) int {
231 if n <= 0 {
232 panic("invalid argument to Intn")
233 }
234 if n <= 1<<31-1 {
235 return int(p.Int31n(int32(n)))
236 }
237 return int(p.Int63n(int64(n)))
238 }
239
240 func (p *siprng) Int63n(n int64) int64 {
241 if n <= 0 {
242 panic("invalid argument to Int63n")
243 }
244 max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
245 v := p.Int63()
246 for v > max {
247 v = p.Int63()
248 }
249 return v % n
250 }
251
252 func (p *siprng) Int31n(n int32) int32 {
253 if n <= 0 {
254 panic("invalid argument to Int31n")
255 }
256 max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
257 v := p.Int31()
258 for v > max {
259 v = p.Int31()
260 }
261 return v % n
262 }
263
264 func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) }
1 package captcha
2
3 import "testing"
4
5 func TestSiphash(t *testing.T) {
6 good := uint64(0xe849e8bb6ffe2567)
7 cur := siphash(0, 0, 0)
8 if cur != good {
9 t.Fatalf("siphash: expected %x, got %x", good, cur)
10 }
11 }
12
13 func BenchmarkSiprng(b *testing.B) {
14 b.SetBytes(8)
15 p := &siprng{}
16 for i := 0; i < b.N; i++ {
17 p.Uint64()
18 }
19 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!