Added test package in nix flake to automatically run tests.

To be able to do such, it was required to add the vendor directory
to the git project.
This commit is contained in:
didier amyot committed 2023-06-10 09:33:04 -04:00
1 parent 459dc26b4f
commit 1f2ea8b7e5
15 files changed
+2619

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
export {
encode,
decode
} from "https://denopkg.com/chiefbiiko/std-encoding@v1.1.1/mod.ts";
+191
View File
@@ -0,0 +1,191 @@
import { encode, decode } from "./deps.ts";
function rotl(x: number, n: number): number {
return (x << n) | (x >>> (32 - n));
}
/** Byte length of a SHA1 digest. */
export const BYTES: number = 20;
/** A class representation of the SHA1 algorithm. */
export class SHA1 {
readonly hashSize: number = BYTES;
private _buf: Uint8Array = new Uint8Array(64);
private _bufIdx!: number;
private _count!: Uint32Array;
private _K: Uint32Array = new Uint32Array([0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]);
private _H!: Uint32Array;
private _finalized!: boolean;
/** Creates a SHA1 instance. */
constructor() {
this.init();
}
/** Reduces the four input numbers to a single one. */
protected static F(t: number, b: number, c: number, d: number): number {
if (t <= 19) {
return (b & c) | (~b & d);
} else if (t <= 39) {
return b ^ c ^ d;
} else if (t <= 59) {
return (b & c) | (b & d) | (c & d);
} else {
return b ^ c ^ d;
}
}
/** Initializes a hash instance. */
init(): SHA1 {
// prettier-ignore
this._H = new Uint32Array([
0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
]);
this._bufIdx = 0;
this._count = new Uint32Array(2);
this._buf.fill(0);
this._finalized = false;
return this;
}
/** Updates a hash with additional message data. */
update(msg: string | Uint8Array, inputEncoding?: string): SHA1 {
if (msg === null) {
throw new TypeError("msg must be a string or Uint8Array.");
} else if (typeof msg === "string") {
msg = encode(msg, inputEncoding) as Uint8Array;
}
// process the msg as many times as possible, the rest is stored in the buffer
// message is processed in 512 bit (64 byte chunks)
for (let i: number = 0; i < msg.length; i++) {
this._buf[this._bufIdx++] = msg[i];
if (this._bufIdx === 64) {
this.transform();
this._bufIdx = 0;
}
}
// counter update (number of message bits)
const c: Uint32Array = this._count;
if ((c[0] += msg.length << 3) < msg.length << 3) {
c[1]++;
}
c[1] += msg.length >>> 29;
return this;
}
/** Finalizes a hash with additional message data. */
digest(outputEncoding?: string): string | Uint8Array {
if (this._finalized) {
throw new Error("digest has already been called.")
}
this._finalized = true;
// append '1'
const b: Uint8Array = this._buf;
let idx: number = this._bufIdx;
b[idx++] = 0x80;
// zeropad up to byte pos 56
while (idx !== 56) {
if (idx === 64) {
this.transform();
idx = 0;
}
b[idx++] = 0;
}
// append length in bits
const c: Uint32Array = this._count;
b[56] = (c[1] >>> 24) & 0xff;
b[57] = (c[1] >>> 16) & 0xff;
b[58] = (c[1] >>> 8) & 0xff;
b[59] = (c[1] >>> 0) & 0xff;
b[60] = (c[0] >>> 24) & 0xff;
b[61] = (c[0] >>> 16) & 0xff;
b[62] = (c[0] >>> 8) & 0xff;
b[63] = (c[0] >>> 0) & 0xff;
this.transform();
// return the hash as byte array (20 bytes)
const hash: Uint8Array = new Uint8Array(BYTES);
for (let i: number = 0; i < 5; i++) {
hash[(i << 2) + 0] = (this._H[i] >>> 24) & 0xff;
hash[(i << 2) + 1] = (this._H[i] >>> 16) & 0xff;
hash[(i << 2) + 2] = (this._H[i] >>> 8) & 0xff;
hash[(i << 2) + 3] = (this._H[i] >>> 0) & 0xff;
}
// clear internal states and prepare for new hash
this.init();
return outputEncoding ? decode(hash, outputEncoding) : hash;
}
/** Performs one transformation cycle. */
private transform(): void {
const h: Uint32Array = this._H;
let a: number = h[0];
let b: number = h[1];
let c: number = h[2];
let d: number = h[3];
let e: number = h[4];
// convert byte buffer to words
const w: Uint32Array = new Uint32Array(80);
for (let i: number = 0; i < 16; i++) {
w[i] =
this._buf[(i << 2) + 3] |
(this._buf[(i << 2) + 2] << 8) |
(this._buf[(i << 2) + 1] << 16) |
(this._buf[i << 2] << 24);
}
for (let t: number = 0; t < 80; t++) {
if (t >= 16) {
w[t] = rotl(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16], 1);
}
const tmp: number =
(rotl(a, 5) +
SHA1.F(t, b, c, d) +
e +
w[t] +
this._K[Math.floor(t / 20)]) |
0;
e = d;
d = c;
c = rotl(b, 30);
b = a;
a = tmp;
}
h[0] = (h[0] + a) | 0;
h[1] = (h[1] + b) | 0;
h[2] = (h[2] + c) | 0;
h[3] = (h[3] + d) | 0;
h[4] = (h[4] + e) | 0;
}
}
/** Generates a SHA1 hash of the input data. */
export function sha1(
msg: string | Uint8Array,
inputEncoding?: string,
outputEncoding?: string
): string | Uint8Array {
return new SHA1().update(msg, inputEncoding).digest(outputEncoding);
}
+56
View File
@@ -0,0 +1,56 @@
import * as base64 from "https://deno.land/x/base64@v0.2.1/mod.ts";
import * as base64url from "https://deno.land/x/base64@v0.2.1/base64url.ts";
const decoder: TextDecoder = new TextDecoder();
const encoder: TextEncoder = new TextEncoder();
/** Serializes a Uint8Array to a hexadecimal string. */
function toHexString(buf: Uint8Array): string {
return buf.reduce(
(hex: string, byte: number): string =>
`${hex}${byte < 16 ? "0" : ""}${byte.toString(16)}`,
"",
);
}
/** Deserializes a Uint8Array from a hexadecimal string. */
function fromHexString(hex: string): Uint8Array {
const len: number = hex.length;
if (len % 2 || !/^[0-9a-fA-F]+$/.test(hex)) {
throw new TypeError("Invalid hex string.");
}
hex = hex.toLowerCase();
const buf: Uint8Array = new Uint8Array(Math.floor(len / 2));
const end: number = len / 2;
for (let i: number = 0; i < end; ++i) {
buf[i] = parseInt(hex.substr(i * 2, 2), 16);
}
return buf;
}
/** Decodes a Uint8Array to utf8-, base64-, or hex-encoded string. */
export function decode(buf: Uint8Array, encoding: string = "utf8"): string {
if (/^utf-?8$/i.test(encoding)) {
return decoder.decode(buf);
} else if (/^base64$/i.test(encoding)) {
return base64.fromUint8Array(buf);
} else if (/^base64url$/i.test(encoding)) {
return base64url.fromUint8Array(buf);
} else if (/^hex(?:adecimal)?$/i.test(encoding)) {
return toHexString(buf);
} else {
throw new TypeError("Unsupported string encoding.");
}
}
export function encode(str: string, encoding: string = "utf8"): Uint8Array {
if (/^utf-?8$/i.test(encoding)) {
return encoder.encode(str);
} else if (/^base64(?:url)?$/i.test(encoding)) {
return base64.toUint8Array(str);
} else if (/^hex(?:adecimal)?$/i.test(encoding)) {
return fromHexString(str);
} else {
throw new TypeError("Unsupported string encoding.");
}
}