all repos — captcha @ master

Go package captcha implements generation and verification of image and audio CAPTCHAs.

siprng.go (view raw)

  1// Copyright 2014 Dmitry Chestnykh. All rights reserved.
  2// Use of this source code is governed by a MIT-style
  3// license that can be found in the LICENSE file.
  4
  5package captcha
  6
  7import "encoding/binary"
  8
  9// siprng is PRNG based on SipHash-2-4.
 10// (Note: it's not safe to use a single siprng from multiple goroutines.)
 11type siprng struct {
 12	k0, k1, ctr uint64
 13}
 14
 15// siphash implements SipHash-2-4, accepting a uint64 as a message.
 16func siphash(k0, k1, m uint64) uint64 {
 17	// Initialization.
 18	v0 := k0 ^ 0x736f6d6570736575
 19	v1 := k1 ^ 0x646f72616e646f6d
 20	v2 := k0 ^ 0x6c7967656e657261
 21	v3 := k1 ^ 0x7465646279746573
 22	t := uint64(8) << 56
 23
 24	// Compression.
 25	v3 ^= m
 26
 27	// Round 1.
 28	v0 += v1
 29	v1 = v1<<13 | v1>>(64-13)
 30	v1 ^= v0
 31	v0 = v0<<32 | v0>>(64-32)
 32
 33	v2 += v3
 34	v3 = v3<<16 | v3>>(64-16)
 35	v3 ^= v2
 36
 37	v0 += v3
 38	v3 = v3<<21 | v3>>(64-21)
 39	v3 ^= v0
 40
 41	v2 += v1
 42	v1 = v1<<17 | v1>>(64-17)
 43	v1 ^= v2
 44	v2 = v2<<32 | v2>>(64-32)
 45
 46	// Round 2.
 47	v0 += v1
 48	v1 = v1<<13 | v1>>(64-13)
 49	v1 ^= v0
 50	v0 = v0<<32 | v0>>(64-32)
 51
 52	v2 += v3
 53	v3 = v3<<16 | v3>>(64-16)
 54	v3 ^= v2
 55
 56	v0 += v3
 57	v3 = v3<<21 | v3>>(64-21)
 58	v3 ^= v0
 59
 60	v2 += v1
 61	v1 = v1<<17 | v1>>(64-17)
 62	v1 ^= v2
 63	v2 = v2<<32 | v2>>(64-32)
 64
 65	v0 ^= m
 66
 67	// Compress last block.
 68	v3 ^= t
 69
 70	// Round 1.
 71	v0 += v1
 72	v1 = v1<<13 | v1>>(64-13)
 73	v1 ^= v0
 74	v0 = v0<<32 | v0>>(64-32)
 75
 76	v2 += v3
 77	v3 = v3<<16 | v3>>(64-16)
 78	v3 ^= v2
 79
 80	v0 += v3
 81	v3 = v3<<21 | v3>>(64-21)
 82	v3 ^= v0
 83
 84	v2 += v1
 85	v1 = v1<<17 | v1>>(64-17)
 86	v1 ^= v2
 87	v2 = v2<<32 | v2>>(64-32)
 88
 89	// Round 2.
 90	v0 += v1
 91	v1 = v1<<13 | v1>>(64-13)
 92	v1 ^= v0
 93	v0 = v0<<32 | v0>>(64-32)
 94
 95	v2 += v3
 96	v3 = v3<<16 | v3>>(64-16)
 97	v3 ^= v2
 98
 99	v0 += v3
100	v3 = v3<<21 | v3>>(64-21)
101	v3 ^= v0
102
103	v2 += v1
104	v1 = v1<<17 | v1>>(64-17)
105	v1 ^= v2
106	v2 = v2<<32 | v2>>(64-32)
107
108	v0 ^= t
109
110	// Finalization.
111	v2 ^= 0xff
112
113	// Round 1.
114	v0 += v1
115	v1 = v1<<13 | v1>>(64-13)
116	v1 ^= v0
117	v0 = v0<<32 | v0>>(64-32)
118
119	v2 += v3
120	v3 = v3<<16 | v3>>(64-16)
121	v3 ^= v2
122
123	v0 += v3
124	v3 = v3<<21 | v3>>(64-21)
125	v3 ^= v0
126
127	v2 += v1
128	v1 = v1<<17 | v1>>(64-17)
129	v1 ^= v2
130	v2 = v2<<32 | v2>>(64-32)
131
132	// Round 2.
133	v0 += v1
134	v1 = v1<<13 | v1>>(64-13)
135	v1 ^= v0
136	v0 = v0<<32 | v0>>(64-32)
137
138	v2 += v3
139	v3 = v3<<16 | v3>>(64-16)
140	v3 ^= v2
141
142	v0 += v3
143	v3 = v3<<21 | v3>>(64-21)
144	v3 ^= v0
145
146	v2 += v1
147	v1 = v1<<17 | v1>>(64-17)
148	v1 ^= v2
149	v2 = v2<<32 | v2>>(64-32)
150
151	// Round 3.
152	v0 += v1
153	v1 = v1<<13 | v1>>(64-13)
154	v1 ^= v0
155	v0 = v0<<32 | v0>>(64-32)
156
157	v2 += v3
158	v3 = v3<<16 | v3>>(64-16)
159	v3 ^= v2
160
161	v0 += v3
162	v3 = v3<<21 | v3>>(64-21)
163	v3 ^= v0
164
165	v2 += v1
166	v1 = v1<<17 | v1>>(64-17)
167	v1 ^= v2
168	v2 = v2<<32 | v2>>(64-32)
169
170	// Round 4.
171	v0 += v1
172	v1 = v1<<13 | v1>>(64-13)
173	v1 ^= v0
174	v0 = v0<<32 | v0>>(64-32)
175
176	v2 += v3
177	v3 = v3<<16 | v3>>(64-16)
178	v3 ^= v2
179
180	v0 += v3
181	v3 = v3<<21 | v3>>(64-21)
182	v3 ^= v0
183
184	v2 += v1
185	v1 = v1<<17 | v1>>(64-17)
186	v1 ^= v2
187	v2 = v2<<32 | v2>>(64-32)
188
189	return v0 ^ v1 ^ v2 ^ v3
190}
191
192// Seed sets a new secret seed for PRNG.
193func (p *siprng) Seed(k [16]byte) {
194	p.k0 = binary.LittleEndian.Uint64(k[0:8])
195	p.k1 = binary.LittleEndian.Uint64(k[8:16])
196	p.ctr = 1
197}
198
199// Uint64 returns a new pseudorandom uint64.
200func (p *siprng) Uint64() uint64 {
201	v := siphash(p.k0, p.k1, p.ctr)
202	p.ctr++
203	return v
204}
205
206func (p *siprng) Bytes(n int) []byte {
207	// Since we don't have a buffer for generated bytes in siprng state,
208	// we just generate enough 8-byte blocks and then cut the result to the
209	// required length. Doing it this way, we lose generated bytes, and we
210	// don't get the strictly sequential deterministic output from PRNG:
211	// calling Uint64() and then Bytes(3) produces different output than
212	// when calling them in the reverse order, but for our applications
213	// this is OK.
214	numBlocks := (n + 8 - 1) / 8
215	b := make([]byte, numBlocks*8)
216	for i := 0; i < len(b); i += 8 {
217		binary.LittleEndian.PutUint64(b[i:], p.Uint64())
218	}
219	return b[:n]
220}
221
222func (p *siprng) Int63() int64 {
223	return int64(p.Uint64() & 0x7fffffffffffffff)
224}
225
226func (p *siprng) Uint32() uint32 {
227	return uint32(p.Uint64())
228}
229
230func (p *siprng) Int31() int32 {
231	return int32(p.Uint32() & 0x7fffffff)
232}
233
234func (p *siprng) Intn(n int) int {
235	if n <= 0 {
236		panic("invalid argument to Intn")
237	}
238	if n <= 1<<31-1 {
239		return int(p.Int31n(int32(n)))
240	}
241	return int(p.Int63n(int64(n)))
242}
243
244func (p *siprng) Int63n(n int64) int64 {
245	if n <= 0 {
246		panic("invalid argument to Int63n")
247	}
248	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
249	v := p.Int63()
250	for v > max {
251		v = p.Int63()
252	}
253	return v % n
254}
255
256func (p *siprng) Int31n(n int32) int32 {
257	if n <= 0 {
258		panic("invalid argument to Int31n")
259	}
260	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
261	v := p.Int31()
262	for v > max {
263		v = p.Int31()
264	}
265	return v % n
266}
267
268func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) }
269
270// Int returns a pseudorandom int in range [from, to].
271func (p *siprng) Int(from, to int) int {
272	return p.Intn(to+1-from) + from
273}
274
275// Float returns a pseudorandom float64 in range [from, to].
276func (p *siprng) Float(from, to float64) float64 {
277	return (to-from)*p.Float64() + from
278}