mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 09:02:25 -05:00 
			
		
		
		
	[chore] more NoLLaMas proof-of-work tweaking (#4096)
- replaces the sha256 calculation with an alternative implementation that seems to use more uniform time-taken across different platforms - goes back to the simpler difficulty calculation without a "partial" difficulty level Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4096 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								c15002d76e
							
						
					
				
			
			
				commit
				
					
						211192c482
					
				
			
		
					 7 changed files with 184 additions and 113 deletions
				
			
		|  | @ -72,8 +72,7 @@ func NoLLaMas( | ||||||
| 	var nollamas nollamas | 	var nollamas nollamas | ||||||
| 	nollamas.seed = seed | 	nollamas.seed = seed | ||||||
| 	nollamas.ttl = time.Hour | 	nollamas.ttl = time.Hour | ||||||
| 	nollamas.diff1 = 4 | 	nollamas.diff = 4 | ||||||
| 	nollamas.diff2 = '4' |  | ||||||
| 	nollamas.getInstanceV1 = getInstanceV1 | 	nollamas.getInstanceV1 = getInstanceV1 | ||||||
| 	nollamas.policy = cookiePolicy | 	nollamas.policy = cookiePolicy | ||||||
| 	return nollamas.Serve | 	return nollamas.Serve | ||||||
|  | @ -101,16 +100,9 @@ type nollamas struct { | ||||||
| 	ttl time.Duration | 	ttl time.Duration | ||||||
| 
 | 
 | ||||||
| 	// algorithm difficulty knobs. | 	// algorithm difficulty knobs. | ||||||
| 	// diff1 determines the number of | 	// diff determines the number | ||||||
| 	// leading zeroes required, while | 	// of leading zeroes required. | ||||||
| 	// diff2 checks the next byte at | 	diff uint8 | ||||||
| 	// index is less than it. |  | ||||||
| 	// |  | ||||||
| 	// e.g. you look for say: |  | ||||||
| 	// - b[0:3] must be '0' |  | ||||||
| 	// - b[4] can be < '5' |  | ||||||
| 	diff1 uint8 |  | ||||||
| 	diff2 uint8 |  | ||||||
| 
 | 
 | ||||||
| 	// extra fields required for | 	// extra fields required for | ||||||
| 	// our template rendering. | 	// our template rendering. | ||||||
|  | @ -187,6 +179,12 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// From here-on out, all | ||||||
|  | 	// possibilities are handled | ||||||
|  | 	// by us. Prevent further http | ||||||
|  | 	// handlers from being called. | ||||||
|  | 	c.Abort() | ||||||
|  | 
 | ||||||
| 	// Prepare new log entry. | 	// Prepare new log entry. | ||||||
| 	l := log.WithContext(ctx). | 	l := log.WithContext(ctx). | ||||||
| 		WithField("userAgent", userAgent). | 		WithField("userAgent", userAgent). | ||||||
|  | @ -225,10 +223,6 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| 
 | 
 | ||||||
| 	l.Infof("challenge passed: %s", nonce) | 	l.Infof("challenge passed: %s", nonce) | ||||||
| 
 | 
 | ||||||
| 	// Don't pass to further |  | ||||||
| 	// handlers, we'll redirect. |  | ||||||
| 	c.Abort() |  | ||||||
| 
 |  | ||||||
| 	// Drop solution query and encode. | 	// Drop solution query and encode. | ||||||
| 	query.Del("nollamas_solution") | 	query.Del("nollamas_solution") | ||||||
| 	c.Request.URL.RawQuery = query.Encode() | 	c.Request.URL.RawQuery = query.Encode() | ||||||
|  | @ -240,11 +234,6 @@ func (m *nollamas) Serve(c *gin.Context) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *nollamas) renderChallenge(c *gin.Context, challenge string) { | func (m *nollamas) renderChallenge(c *gin.Context, challenge string) { | ||||||
| 	// Don't pass to further |  | ||||||
| 	// handlers, they only get |  | ||||||
| 	// our challenge page. |  | ||||||
| 	c.Abort() |  | ||||||
| 
 |  | ||||||
| 	// Fetch current instance information for templating vars. | 	// Fetch current instance information for templating vars. | ||||||
| 	instance, errWithCode := m.getInstanceV1(c.Request.Context()) | 	instance, errWithCode := m.getInstanceV1(c.Request.Context()) | ||||||
| 	if errWithCode != nil { | 	if errWithCode != nil { | ||||||
|  | @ -263,12 +252,8 @@ func (m *nollamas) renderChallenge(c *gin.Context, challenge string) { | ||||||
| 			"/assets/Fork-Awesome/css/fork-awesome.min.css", | 			"/assets/Fork-Awesome/css/fork-awesome.min.css", | ||||||
| 		}, | 		}, | ||||||
| 		Extra: map[string]any{ | 		Extra: map[string]any{ | ||||||
| 			"challenge":   challenge, | 			"challenge":  challenge, | ||||||
| 			"difficulty1": m.diff1, | 			"difficulty": m.diff, | ||||||
| 
 |  | ||||||
| 			// must be a str otherwise template |  | ||||||
| 			// renders uint8 as int, not char |  | ||||||
| 			"difficulty2": hexStrs[m.diff2], |  | ||||||
| 		}, | 		}, | ||||||
| 		Javascript: []apiutil.JavascriptEntry{ | 		Javascript: []apiutil.JavascriptEntry{ | ||||||
| 			{ | 			{ | ||||||
|  | @ -289,8 +274,7 @@ func (m *nollamas) token(hash *hashWithBufs, userAgent, clientIP string) string | ||||||
| 	// Include difficulty level in | 	// Include difficulty level in | ||||||
| 	// hash input data so if config | 	// hash input data so if config | ||||||
| 	// changes then token invalidates. | 	// changes then token invalidates. | ||||||
| 	hash.hash.Write([]byte{m.diff1}) | 	hash.hash.Write([]byte{m.diff}) | ||||||
| 	hash.hash.Write([]byte{m.diff2}) |  | ||||||
| 
 | 
 | ||||||
| 	// Also seed the generated input with | 	// Also seed the generated input with | ||||||
| 	// current time rounded to TTL, so our | 	// current time rounded to TTL, so our | ||||||
|  | @ -326,40 +310,18 @@ func (m *nollamas) checkChallenge(hash *hashWithBufs, challenge, nonce string) b | ||||||
| 	hex.Encode(hash.ebuf, hash.hbuf) | 	hex.Encode(hash.ebuf, hash.hbuf) | ||||||
| 	solution := hash.ebuf | 	solution := hash.ebuf | ||||||
| 
 | 
 | ||||||
| 	// Compiler bound-check-elimination hint. | 	// Compiler bound-check hint. | ||||||
| 	if len(solution) < int(m.diff1+1) { | 	if len(solution) < int(m.diff) { | ||||||
| 		panic(gtserror.New("BCE")) | 		panic(gtserror.New("BCE")) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Check that the first 'diff' | 	// Check that the first 'diff' | ||||||
| 	// many chars are indeed zeroes. | 	// many chars are indeed zeroes. | ||||||
| 	for i := range m.diff1 { | 	for i := range m.diff { | ||||||
| 		if solution[i] != '0' { | 		if solution[i] != '0' { | ||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Check that next char is < 'diff2'. | 	return true | ||||||
| 	return solution[m.diff1] < m.diff2 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // hexStrs is a quick lookup of ASCII hex |  | ||||||
| // bytes to their string equivalent. |  | ||||||
| var hexStrs = [...]string{ |  | ||||||
| 	'0': "0", |  | ||||||
| 	'1': "1", |  | ||||||
| 	'2': "2", |  | ||||||
| 	'3': "3", |  | ||||||
| 	'4': "4", |  | ||||||
| 	'5': "5", |  | ||||||
| 	'6': "6", |  | ||||||
| 	'7': "7", |  | ||||||
| 	'8': "8", |  | ||||||
| 	'9': "9", |  | ||||||
| 	'a': "a", |  | ||||||
| 	'b': "b", |  | ||||||
| 	'c': "c", |  | ||||||
| 	'd': "d", |  | ||||||
| 	'e': "e", |  | ||||||
| 	'f': "f", |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -96,8 +96,7 @@ func testNoLLaMasMiddleware(t *testing.T, e *gin.Engine, userAgent string) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var challenge string | 	var challenge string | ||||||
| 	var diff1 uint64 | 	var difficulty uint64 | ||||||
| 	var diff2 uint8 |  | ||||||
| 
 | 
 | ||||||
| 	// Parse output body and find the challenge / difficulty. | 	// Parse output body and find the challenge / difficulty. | ||||||
| 	for _, line := range strings.Split(string(b), "\n") { | 	for _, line := range strings.Split(string(b), "\n") { | ||||||
|  | @ -107,22 +106,17 @@ func testNoLLaMasMiddleware(t *testing.T, e *gin.Engine, userAgent string) { | ||||||
| 			line = line[25:] | 			line = line[25:] | ||||||
| 			line = line[:len(line)-1] | 			line = line[:len(line)-1] | ||||||
| 			challenge = line | 			challenge = line | ||||||
| 		case strings.HasPrefix(line, "data-nollamas-difficulty1=\""): | 		case strings.HasPrefix(line, "data-nollamas-difficulty=\""): | ||||||
| 			line = line[27:] | 			line = line[26:] | ||||||
| 			line = line[:len(line)-1] | 			line = line[:len(line)-1] | ||||||
| 			var err error | 			var err error | ||||||
| 			diff1, err = strconv.ParseUint(line, 10, 8) | 			difficulty, err = strconv.ParseUint(line, 10, 8) | ||||||
| 			assert.NoError(t, err) | 			assert.NoError(t, err) | ||||||
| 		case strings.HasPrefix(line, "data-nollamas-difficulty2=\""): |  | ||||||
| 			line = line[27:] |  | ||||||
| 			line = line[:len(line)-1] |  | ||||||
| 			diff2 = line[0] |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Ensure valid posed challenge. | 	// Ensure valid posed challenge. | ||||||
| 	assert.NotZero(t, diff1) | 	assert.NotZero(t, difficulty) | ||||||
| 	assert.NotZero(t, diff2) |  | ||||||
| 	assert.NotEmpty(t, challenge) | 	assert.NotEmpty(t, challenge) | ||||||
| 
 | 
 | ||||||
| 	// Prepare a test request for gin engine. | 	// Prepare a test request for gin engine. | ||||||
|  | @ -131,12 +125,11 @@ func testNoLLaMasMiddleware(t *testing.T, e *gin.Engine, userAgent string) { | ||||||
| 	rw = httptest.NewRecorder() | 	rw = httptest.NewRecorder() | ||||||
| 
 | 
 | ||||||
| 	// Now compute and set solution query paramater. | 	// Now compute and set solution query paramater. | ||||||
| 	solution := computeSolution(challenge, diff1, diff2) | 	solution := computeSolution(challenge, difficulty) | ||||||
| 	r.URL.RawQuery = "nollamas_solution=" + solution | 	r.URL.RawQuery = "nollamas_solution=" + solution | ||||||
| 
 | 
 | ||||||
| 	t.Logf("challenge=%s", challenge) | 	t.Logf("challenge=%s", challenge) | ||||||
| 	t.Logf("diff1=%d", diff1) | 	t.Logf("difficulty=%d", difficulty) | ||||||
| 	t.Logf("diff2='%c'", diff2) |  | ||||||
| 	t.Logf("solution=%s", solution) | 	t.Logf("solution=%s", solution) | ||||||
| 
 | 
 | ||||||
| 	// Pass req through | 	// Pass req through | ||||||
|  | @ -159,21 +152,18 @@ func testNoLLaMasMiddleware(t *testing.T, e *gin.Engine, userAgent string) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // computeSolution does the functional equivalent of our nollamas workerTask.js. | // computeSolution does the functional equivalent of our nollamas workerTask.js. | ||||||
| func computeSolution(challenge string, diff1 uint64, diff2 uint8) string { | func computeSolution(challenge string, diff uint64) string { | ||||||
| outer: | outer: | ||||||
| 	for i := 0; ; i++ { | 	for i := 0; ; i++ { | ||||||
| 		solution := strconv.Itoa(i) | 		solution := strconv.Itoa(i) | ||||||
| 		combined := challenge + solution | 		combined := challenge + solution | ||||||
| 		hash := sha256.Sum256(byteutil.S2B(combined)) | 		hash := sha256.Sum256(byteutil.S2B(combined)) | ||||||
| 		encoded := hex.EncodeToString(hash[:]) | 		encoded := hex.EncodeToString(hash[:]) | ||||||
| 		for i := range diff1 { | 		for i := range diff { | ||||||
| 			if encoded[i] != '0' { | 			if encoded[i] != '0' { | ||||||
| 				continue outer | 				continue outer | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if encoded[diff1] >= diff2 { |  | ||||||
| 			continue outer |  | ||||||
| 		} |  | ||||||
| 		return solution | 		return solution | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
| node_modules | node_modules | ||||||
| prism.js | prism.js | ||||||
| prism.css | prism.css | ||||||
|  | nollamasworker/sha256.js | ||||||
|  | @ -19,7 +19,7 @@ | ||||||
| 
 | 
 | ||||||
| const explanation = "Your browser is currently solving a proof-of-work challenge designed to deter \"ai\" scrapers. This should take no more than a few seconds..."; | const explanation = "Your browser is currently solving a proof-of-work challenge designed to deter \"ai\" scrapers. This should take no more than a few seconds..."; | ||||||
| 
 | 
 | ||||||
| document.addEventListener('DOMContentLoaded', function() { | document.addEventListener("DOMContentLoaded", function() { | ||||||
| 	// Get the nollamas section container.
 | 	// Get the nollamas section container.
 | ||||||
| 	const nollamas = document.querySelector(".nollamas"); | 	const nollamas = document.querySelector(".nollamas"); | ||||||
| 
 | 
 | ||||||
|  | @ -44,20 +44,17 @@ document.addEventListener('DOMContentLoaded', function() { | ||||||
| 	// Read the challenge and difficulty from
 | 	// Read the challenge and difficulty from
 | ||||||
| 	// data attributes on the nollamas section.
 | 	// data attributes on the nollamas section.
 | ||||||
| 	const challenge = nollamas.dataset.nollamasChallenge; | 	const challenge = nollamas.dataset.nollamasChallenge; | ||||||
| 	const difficulty1 = nollamas.dataset.nollamasDifficulty1; | 	const difficulty = nollamas.dataset.nollamasDifficulty; | ||||||
| 	const difficulty2 = nollamas.dataset.nollamasDifficulty2; |  | ||||||
| 
 | 
 | ||||||
| 	console.log('challenge:', challenge);     // eslint-disable-line no-console
 | 	console.log("challenge:", challenge);     // eslint-disable-line no-console
 | ||||||
| 	console.log('difficulty1:', difficulty1); // eslint-disable-line no-console
 | 	console.log("difficulty:", difficulty); // eslint-disable-line no-console
 | ||||||
| 	console.log('difficulty2:', difficulty2); // eslint-disable-line no-console
 |  | ||||||
| 
 | 
 | ||||||
| 	// Prepare the worker with task function.
 | 	// Prepare the worker with task function.
 | ||||||
| 	const worker = new Worker("/assets/dist/nollamasworker.js"); | 	const worker = new Worker("/assets/dist/nollamasworker.js"); | ||||||
| 	const startTime = performance.now(); | 	const startTime = performance.now(); | ||||||
| 	worker.postMessage({ | 	worker.postMessage({ | ||||||
| 		challenge: challenge, | 		challenge: challenge, | ||||||
| 		difficulty1: difficulty1, | 		difficulty: difficulty, | ||||||
| 		difficulty2: difficulty2, |  | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	// Set the main worker function.
 | 	// Set the main worker function.
 | ||||||
|  | @ -79,7 +76,8 @@ document.addEventListener('DOMContentLoaded', function() { | ||||||
| 			solutionWrapper.appendChild(tick); | 			solutionWrapper.appendChild(tick); | ||||||
| 
 | 
 | ||||||
| 			const took = document.createElement("span"); | 			const took = document.createElement("span"); | ||||||
| 			took.appendChild(document.createTextNode(`Solved in ${duration.toString()}ms!`)); | 			const solvedText = `Solved after ${e.data.nonce} iterations, in ${duration.toString()}ms!`; | ||||||
|  | 			took.appendChild(document.createTextNode(solvedText)); | ||||||
| 			solutionWrapper.appendChild(took); | 			solutionWrapper.appendChild(took); | ||||||
| 
 | 
 | ||||||
| 			nollamas.appendChild(solutionWrapper); | 			nollamas.appendChild(solutionWrapper); | ||||||
|  | @ -89,7 +87,7 @@ document.addEventListener('DOMContentLoaded', function() { | ||||||
| 			// not so long that they have to wait unduly.
 | 			// not so long that they have to wait unduly.
 | ||||||
| 			setTimeout(() => { | 			setTimeout(() => { | ||||||
| 				let url = new URL(window.location.href); | 				let url = new URL(window.location.href); | ||||||
| 				url.searchParams.set('nollamas_solution', e.data.nonce); | 				url.searchParams.set("nollamas_solution", e.data.nonce); | ||||||
| 				window.location.replace(url.toString()); | 				window.location.replace(url.toString()); | ||||||
| 			}, 500); | 			}, 500); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -17,43 +17,51 @@ | ||||||
| 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| onmessage = async function(e) { | import sha256 from "./sha256"; | ||||||
| 	console.log('worker started'); // eslint-disable-line no-console
 |  | ||||||
| 
 | 
 | ||||||
| 	const challenge = e.data.challenge; | let compute = async function(challengeStr, diffStr) { | ||||||
| 	const textEncoder = new TextEncoder(); | 	const textEncoder = new TextEncoder(); | ||||||
| 
 | 
 | ||||||
| 	// Get difficulty and generate the expected
 | 	// Get difficulty1 as number and generate
 | ||||||
| 	// zero ASCII prefix to check for in hashes.
 | 	// expected zero ASCII prefix to check for.
 | ||||||
| 	const difficulty1Str = e.data.difficulty1; | 	const diff1 = parseInt(diffStr, 10); | ||||||
| 	const difficulty2Str = e.data.difficulty2; | 	const zeros = "0".repeat(diff1); | ||||||
| 	const difficulty1 = parseInt(difficulty1Str, 10); | 
 | ||||||
| 	const zeroPrefix = '0'.repeat(difficulty1); | 	// Calculate hex encoded prefix required to check solution, where we
 | ||||||
|  | 	// need diff1 no. chars in hex, and hex encoding doubles input length.
 | ||||||
|  | 	const prefixLen = diff1 / 2 + (diff1 % 2 != 0 ? 2 : 0); | ||||||
| 
 | 
 | ||||||
| 	let nonce = 0; | 	let nonce = 0; | ||||||
| 	while (true) { // eslint-disable-line no-constant-condition
 | 	while (true) { // eslint-disable-line no-constant-condition
 | ||||||
| 
 | 
 | ||||||
| 		// Create possible solution string from challenge + nonce.
 | 		// Create possible solution string from challenge string + nonce.
 | ||||||
| 		const solution = textEncoder.encode(challenge + nonce.toString()); | 		const solution = textEncoder.encode(challengeStr + nonce.toString()); | ||||||
| 
 | 
 | ||||||
| 		// Generate SHA256 hashsum of solution string and hex encode the result.
 | 		// Generate SHA256 hashsum of solution string, and hex encode the
 | ||||||
| 		const hashBuffer = await crypto.subtle.digest('SHA-256', solution); | 		// necessary prefix length we need to check for a valid solution.
 | ||||||
| 		const hashArray = Array.from(new Uint8Array(hashBuffer)); | 		const prefixArray = Array.from(sha256(solution).slice(0, prefixLen)); | ||||||
| 		const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); | 		const prefixHex = prefixArray.map(b => b.toString(16).padStart(2, "0")).join(""); | ||||||
| 
 | 
 | ||||||
| 		// Check if the hex encoded hash has
 | 		// Check if the hex encoded hash has
 | ||||||
| 		// difficulty defined zeroes prefix.
 | 		// difficulty defined zeroes prefix.
 | ||||||
| 		if (hashHex.startsWith(zeroPrefix)) { | 		if (prefixHex.startsWith(zeros)) { | ||||||
| 
 | 			return nonce; | ||||||
| 			// Check if the next char after zero prefix
 |  | ||||||
| 			// is specifically less than difficulty2 char.
 |  | ||||||
| 			if (hashHex.charAt(difficulty1) < difficulty2Str) { |  | ||||||
| 				postMessage({ nonce: nonce, done: true }); |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Iter.
 | 		// Iter.
 | ||||||
| 		nonce++; | 		nonce++; | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | onmessage = async function(e) { | ||||||
|  | 	console.log('worker started'); // eslint-disable-line no-console
 | ||||||
|  | 
 | ||||||
|  | 	const challenge = e.data.challenge; | ||||||
|  | 	const difficulty = e.data.difficulty; | ||||||
|  | 
 | ||||||
|  | 	// Compute the nonce that produces solution with args.
 | ||||||
|  | 	let nonce = await compute(challenge, difficulty); | ||||||
|  | 
 | ||||||
|  | 	// Post the solution nonce back to caller.
 | ||||||
|  | 	postMessage({ nonce: nonce, done: true }); | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										113
									
								
								web/source/nollamasworker/sha256.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								web/source/nollamasworker/sha256.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | ||||||
|  | /* | ||||||
|  |     Copyright 2022 Andrea Griffini | ||||||
|  | 
 | ||||||
|  |     Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  |     a copy of this software and associated documentation files (the | ||||||
|  |     "Software"), to deal in the Software without restriction, including | ||||||
|  |     without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  |     distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  |     permit persons to whom the Software is furnished to do so, subject to | ||||||
|  |     the following conditions: | ||||||
|  | 
 | ||||||
|  |     The above copyright notice and this permission notice shall be | ||||||
|  |     included in all copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  |     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
|  |     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  |     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
|  |     LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
|  |     OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  |     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  | 
 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | // sha256(data) returns the digest of an input piece of data.
 | ||||||
|  | // sha256(none) returns an object you can call .add(data), and .digest() at the end.
 | ||||||
|  | // the returned digest is a 32-byte Uint8Array instance with an added .hex() function.
 | ||||||
|  | // input should be string (that will be encoded as UTF-8) or an array-like with values 0..255.
 | ||||||
|  | // source: https://github.com/6502/sha256
 | ||||||
|  | export default function sha256(data) { | ||||||
|  | 	let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a, | ||||||
|  | 		h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19, | ||||||
|  | 		tsz = 0, bp = 0; | ||||||
|  | 	const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | ||||||
|  | 			0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | ||||||
|  | 			0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | ||||||
|  | 			0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | ||||||
|  | 			0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | ||||||
|  | 			0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | ||||||
|  | 			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | ||||||
|  | 			0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2], | ||||||
|  | 		rrot = (x, n) => (x >>> n) | (x << (32-n)), | ||||||
|  | 		w = new Uint32Array(64), | ||||||
|  | 		buf = new Uint8Array(64), | ||||||
|  | 		process = () => { | ||||||
|  | 			for (let j=0,r=0; j<16; j++,r+=4) { | ||||||
|  | 				w[j] = (buf[r]<<24) | (buf[r+1]<<16) | (buf[r+2]<<8) | buf[r+3]; | ||||||
|  | 			} | ||||||
|  | 			for (let j=16; j<64; j++) { | ||||||
|  | 				let s0 = rrot(w[j-15], 7) ^ rrot(w[j-15], 18) ^ (w[j-15] >>> 3); | ||||||
|  | 				let s1 = rrot(w[j-2], 17) ^ rrot(w[j-2], 19) ^ (w[j-2] >>> 10); | ||||||
|  | 				w[j] = (w[j-16] + s0 + w[j-7] + s1) | 0; | ||||||
|  | 			} | ||||||
|  | 			let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7; | ||||||
|  | 			for (let j=0; j<64; j++) { | ||||||
|  | 				let S1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25), | ||||||
|  | 					ch = (e & f) ^ ((~e) & g), | ||||||
|  | 					t1 = (h + S1 + ch + k[j] + w[j]) | 0, | ||||||
|  | 					S0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22), | ||||||
|  | 					maj = (a & b) ^ (a & c) ^ (b & c), | ||||||
|  | 					t2 = (S0 + maj) | 0; | ||||||
|  | 				h = g; g = f; f = e; e = (d + t1)|0; d = c; c = b; b = a; a = (t1 + t2)|0; | ||||||
|  | 			} | ||||||
|  | 			h0 = (h0 + a)|0; h1 = (h1 + b)|0; h2 = (h2 + c)|0; h3 = (h3 + d)|0; | ||||||
|  | 			h4 = (h4 + e)|0; h5 = (h5 + f)|0; h6 = (h6 + g)|0; h7 = (h7 + h)|0; | ||||||
|  | 			bp = 0; | ||||||
|  | 		}, | ||||||
|  | 		add = data => { | ||||||
|  | 			if (typeof data === "string") { | ||||||
|  | 				data = typeof TextEncoder === "undefined" ? Buffer.from(data) : (new TextEncoder).encode(data); | ||||||
|  | 			} | ||||||
|  | 			for (let i=0; i<data.length; i++) { | ||||||
|  | 				buf[bp++] = data[i]; | ||||||
|  | 				if (bp === 64) {process();} | ||||||
|  | 			} | ||||||
|  | 			tsz += data.length; | ||||||
|  | 		}, | ||||||
|  | 		digest = () => { | ||||||
|  | 			buf[bp++] = 0x80; if (bp == 64) {process();} | ||||||
|  | 			if (bp + 8 > 64) { | ||||||
|  | 				while (bp < 64) {buf[bp++] = 0x00;} | ||||||
|  | 				process(); | ||||||
|  | 			} | ||||||
|  | 			while (bp < 58) {buf[bp++] = 0x00;} | ||||||
|  | 			// Max number of bytes is 35,184,372,088,831
 | ||||||
|  | 			let L = tsz * 8; | ||||||
|  | 			buf[bp++] = (L / 1099511627776.) & 255; | ||||||
|  | 			buf[bp++] = (L / 4294967296.) & 255; | ||||||
|  | 			buf[bp++] = L >>> 24; | ||||||
|  | 			buf[bp++] = (L >>> 16) & 255; | ||||||
|  | 			buf[bp++] = (L >>> 8) & 255; | ||||||
|  | 			buf[bp++] = L & 255; | ||||||
|  | 			process(); | ||||||
|  | 			let reply = new Uint8Array(32); | ||||||
|  | 			reply[ 0] = h0 >>> 24; reply[ 1] = (h0 >>> 16) & 255; reply[ 2] = (h0 >>> 8) & 255; reply[ 3] = h0 & 255; | ||||||
|  | 			reply[ 4] = h1 >>> 24; reply[ 5] = (h1 >>> 16) & 255; reply[ 6] = (h1 >>> 8) & 255; reply[ 7] = h1 & 255; | ||||||
|  | 			reply[ 8] = h2 >>> 24; reply[ 9] = (h2 >>> 16) & 255; reply[10] = (h2 >>> 8) & 255; reply[11] = h2 & 255; | ||||||
|  | 			reply[12] = h3 >>> 24; reply[13] = (h3 >>> 16) & 255; reply[14] = (h3 >>> 8) & 255; reply[15] = h3 & 255; | ||||||
|  | 			reply[16] = h4 >>> 24; reply[17] = (h4 >>> 16) & 255; reply[18] = (h4 >>> 8) & 255; reply[19] = h4 & 255; | ||||||
|  | 			reply[20] = h5 >>> 24; reply[21] = (h5 >>> 16) & 255; reply[22] = (h5 >>> 8) & 255; reply[23] = h5 & 255; | ||||||
|  | 			reply[24] = h6 >>> 24; reply[25] = (h6 >>> 16) & 255; reply[26] = (h6 >>> 8) & 255; reply[27] = h6 & 255; | ||||||
|  | 			reply[28] = h7 >>> 24; reply[29] = (h7 >>> 16) & 255; reply[30] = (h7 >>> 8) & 255; reply[31] = h7 & 255; | ||||||
|  | 			reply.hex = () => { | ||||||
|  | 				let res = ""; | ||||||
|  | 				reply.forEach(x => res += ("0" + x.toString(16)).slice(-2)); // eslint-disable-line no-return-assign
 | ||||||
|  | 				return res; | ||||||
|  | 			}; | ||||||
|  | 			return reply; | ||||||
|  | 		}; | ||||||
|  | 	if (data === undefined) {return {add, digest};} | ||||||
|  | 	add(data); | ||||||
|  | 	return digest(); | ||||||
|  | } | ||||||
|  | @ -21,8 +21,7 @@ | ||||||
| <main> | <main> | ||||||
|     <section class="nollamas" |     <section class="nollamas" | ||||||
|         data-nollamas-challenge="{{ .challenge }}" |         data-nollamas-challenge="{{ .challenge }}" | ||||||
|         data-nollamas-difficulty1="{{ .difficulty1 }}" |         data-nollamas-difficulty="{{ .difficulty }}" | ||||||
|         data-nollamas-difficulty2="{{ .difficulty2 }}" |  | ||||||
|     > |     > | ||||||
|         <h1>Checking you're not a creepy crawler...</h1> |         <h1>Checking you're not a creepy crawler...</h1> | ||||||
|         <noscript> |         <noscript> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue