Updates using noble single file modules
This commit is contained in:
@@ -10,6 +10,7 @@ self.addEventListener("install", (event) => {
|
||||
"safari-notifications.js",
|
||||
"nacl.js",
|
||||
"noble-curves.js",
|
||||
"noble-hashes.js",
|
||||
);
|
||||
console.log("scripts imported", event);
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
3068
sw_scripts/noble-hashes.js
Normal file
3068
sw_scripts/noble-hashes.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,340 +1,346 @@
|
||||
async function generateSHA256Hash(data) {
|
||||
const buffer = new TextEncoder().encode(data);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
|
||||
const hashHex = hashArray
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
return hashHex;
|
||||
}
|
||||
|
||||
function bufferFromBase64(base64) {
|
||||
const binaryString = atob(base64);
|
||||
const length = binaryString.length;
|
||||
const bytes = new Uint8Array(length);
|
||||
const binaryString = atob(base64);
|
||||
const length = binaryString.length;
|
||||
const bytes = new Uint8Array(length);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
for (let i = 0; i < length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function fromString(str, encoding = 'utf8') {
|
||||
if (encoding === 'utf8') {
|
||||
return new TextEncoder().encode(str);
|
||||
} else if (encoding === 'base16') {
|
||||
if (str.length % 2 !== 0) {
|
||||
throw new Error('Invalid hex string length.');
|
||||
}
|
||||
let bytes = new Uint8Array(str.length / 2);
|
||||
for (let i = 0; i < str.length; i += 2) {
|
||||
bytes[i/2] = parseInt(str.substring(i, i + 2), 16);
|
||||
}
|
||||
return bytes;
|
||||
|
||||
} else if (encoding === 'base64url') {
|
||||
str = str.replace(/-/g, '+').replace(/_/g, '/');
|
||||
while (str.length % 4) {
|
||||
str += '=';
|
||||
}
|
||||
return new Uint8Array(bufferFromBase64(str));
|
||||
} else {
|
||||
throw new Error(`Unsupported encoding "${encoding}"`);
|
||||
}
|
||||
function fromString(str, encoding = "utf8") {
|
||||
if (encoding === "utf8") {
|
||||
return new TextEncoder().encode(str);
|
||||
} else if (encoding === "base16") {
|
||||
if (str.length % 2 !== 0) {
|
||||
throw new Error("Invalid hex string length.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a Uint8Array to a string with the given encoding.
|
||||
*
|
||||
* @param {Uint8Array} byteArray - The Uint8Array to convert.
|
||||
* @param {string} [encoding='utf8'] - The desired encoding ('utf8', 'base16', 'base64url').
|
||||
* @returns {string} - The encoded string.
|
||||
* @throws {Error} - Throws an error if the encoding is unsupported.
|
||||
*/
|
||||
function toString(byteArray, encoding = 'utf8') {
|
||||
switch (encoding) {
|
||||
case 'utf8':
|
||||
return decodeUTF8(byteArray);
|
||||
case 'base16':
|
||||
return toBase16(byteArray);
|
||||
case 'base64url':
|
||||
return toBase64Url(byteArray);
|
||||
default:
|
||||
throw new Error(`Unsupported encoding "${encoding}"`);
|
||||
}
|
||||
let bytes = new Uint8Array(str.length / 2);
|
||||
for (let i = 0; i < str.length; i += 2) {
|
||||
bytes[i / 2] = parseInt(str.substring(i, i + 2), 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Uint8Array as a UTF-8 string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function decodeUTF8(byteArray) {
|
||||
return new TextDecoder().decode(byteArray);
|
||||
return bytes;
|
||||
} else if (encoding === "base64url") {
|
||||
str = str.replace(/-/g, "+").replace(/_/g, "/");
|
||||
while (str.length % 4) {
|
||||
str += "=";
|
||||
}
|
||||
return new Uint8Array(bufferFromBase64(str));
|
||||
} else {
|
||||
throw new Error(`Unsupported encoding "${encoding}"`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Uint8Array to a base16 (hex) encoded string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function toBase16(byteArray) {
|
||||
return Array.from(byteArray).map(byte => byte.toString(16).padStart(2, '0')).join('');
|
||||
/**
|
||||
* Convert a Uint8Array to a string with the given encoding.
|
||||
*
|
||||
* @param {Uint8Array} byteArray - The Uint8Array to convert.
|
||||
* @param {string} [encoding='utf8'] - The desired encoding ('utf8', 'base16', 'base64url').
|
||||
* @returns {string} - The encoded string.
|
||||
* @throws {Error} - Throws an error if the encoding is unsupported.
|
||||
*/
|
||||
function toString(byteArray, encoding = "utf8") {
|
||||
switch (encoding) {
|
||||
case "utf8":
|
||||
return decodeUTF8(byteArray);
|
||||
case "base16":
|
||||
return toBase16(byteArray);
|
||||
case "base64url":
|
||||
return toBase64Url(byteArray);
|
||||
default:
|
||||
throw new Error(`Unsupported encoding "${encoding}"`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Uint8Array as a UTF-8 string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function decodeUTF8(byteArray) {
|
||||
return new TextDecoder().decode(byteArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Uint8Array to a base16 (hex) encoded string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function toBase16(byteArray) {
|
||||
return Array.from(byteArray)
|
||||
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Uint8Array to a base64url encoded string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function toBase64Url(byteArray) {
|
||||
let uint8Array = new Uint8Array(byteArray);
|
||||
let binaryString = "";
|
||||
for (let i = 0; i < uint8Array.length; i++) {
|
||||
binaryString += String.fromCharCode(uint8Array[i]);
|
||||
}
|
||||
|
||||
// Encode to base64
|
||||
let base64 = btoa(binaryString);
|
||||
|
||||
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
}
|
||||
|
||||
const u8a = { toString, fromString };
|
||||
|
||||
function sha256(payload) {
|
||||
const data = typeof payload === "string" ? u8a.fromString(payload) : payload;
|
||||
return nobleHashes.sha256(data);
|
||||
}
|
||||
|
||||
async function accessToken(identifier) {
|
||||
const did = identifier["did"];
|
||||
const privateKeyHex = identifier["keys"][0]["privateKeyHex"];
|
||||
|
||||
const signer = await SimpleSigner(privateKeyHex);
|
||||
|
||||
const nowEpoch = Math.floor(Date.now() / 1000);
|
||||
const endEpoch = nowEpoch + 60; // add one minute
|
||||
|
||||
const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did };
|
||||
const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R
|
||||
const jwt = await createJWT(tokenPayload, {
|
||||
alg,
|
||||
issuer: did,
|
||||
signer,
|
||||
});
|
||||
console.error(jwt);
|
||||
return jwt;
|
||||
}
|
||||
|
||||
async function createJWT(payload, options, header = {}) {
|
||||
const { issuer, signer, alg, expiresIn, canonicalize } = options;
|
||||
|
||||
if (!signer)
|
||||
throw new Error(
|
||||
"missing_signer: No Signer functionality has been configured",
|
||||
);
|
||||
if (!issuer)
|
||||
throw new Error("missing_issuer: No issuing DID has been configured");
|
||||
if (!header.typ) header.typ = "JWT";
|
||||
if (!header.alg) header.alg = alg;
|
||||
|
||||
const timestamps = {
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
exp: undefined,
|
||||
};
|
||||
|
||||
if (expiresIn) {
|
||||
if (typeof expiresIn === "number") {
|
||||
timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn);
|
||||
} else {
|
||||
throw new Error("invalid_argument: JWT expiresIn is not a number");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Uint8Array to a base64url encoded string.
|
||||
*
|
||||
* @param {Uint8Array} byteArray
|
||||
* @returns {string}
|
||||
*/
|
||||
function toBase64Url(byteArray) {
|
||||
let uint8Array = new Uint8Array(byteArray);
|
||||
let binaryString = '';
|
||||
for (let i = 0; i < uint8Array.length; i++) {
|
||||
binaryString += String.fromCharCode(uint8Array[i]);
|
||||
}
|
||||
const fullPayload = { ...timestamps, ...payload, iss: issuer };
|
||||
return createJWS(fullPayload, signer, header, { canonicalize });
|
||||
}
|
||||
|
||||
// Encode to base64
|
||||
let base64 = btoa(binaryString);
|
||||
|
||||
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
const defaultAlg = "ES256K";
|
||||
|
||||
async function createJWS(payload, signer, header = {}, options = {}) {
|
||||
if (!header.alg) header.alg = defaultAlg;
|
||||
const encodedPayload =
|
||||
typeof payload === "string"
|
||||
? payload
|
||||
: encodeSection(payload, options.canonicalize);
|
||||
const signingInput = [
|
||||
encodeSection(header, options.canonicalize),
|
||||
encodedPayload,
|
||||
].join(".");
|
||||
|
||||
const jwtSigner = ES256KSignerAlg(false);
|
||||
const signature = await jwtSigner(signingInput, signer);
|
||||
|
||||
// JWS Compact Serialization
|
||||
// https://www.rfc-editor.org/rfc/rfc7515#section-7.1
|
||||
return [signingInput, signature].join(".");
|
||||
}
|
||||
|
||||
function canonicalizeData(object) {
|
||||
if (typeof object === "number" && isNaN(object)) {
|
||||
throw new Error("NaN is not allowed");
|
||||
}
|
||||
|
||||
if (typeof object === "number" && !isFinite(object)) {
|
||||
throw new Error("Infinity is not allowed");
|
||||
}
|
||||
|
||||
if (object === null || typeof object !== "object") {
|
||||
return JSON.stringify(object);
|
||||
}
|
||||
|
||||
if (object.toJSON instanceof Function) {
|
||||
return serialize(object.toJSON());
|
||||
}
|
||||
|
||||
if (Array.isArray(object)) {
|
||||
const values = object.reduce((t, cv, ci) => {
|
||||
const comma = ci === 0 ? "" : ",";
|
||||
const value = cv === undefined || typeof cv === "symbol" ? null : cv;
|
||||
return `${t}${comma}${serialize(value)}`;
|
||||
}, "");
|
||||
return `[${values}]`;
|
||||
}
|
||||
|
||||
const values = Object.keys(object)
|
||||
.sort()
|
||||
.reduce((t, cv) => {
|
||||
if (object[cv] === undefined || typeof object[cv] === "symbol") {
|
||||
return t;
|
||||
}
|
||||
const comma = t.length === 0 ? "" : ",";
|
||||
return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`;
|
||||
}, "");
|
||||
return `{${values}}`;
|
||||
}
|
||||
|
||||
function encodeSection(data, shouldCanonicalize = false) {
|
||||
if (shouldCanonicalize) {
|
||||
return encodeBase64url(canonicalizeData(data));
|
||||
} else {
|
||||
return encodeBase64url(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
function encodeBase64url(s) {
|
||||
return bytesToBase64url(u8a.fromString(s));
|
||||
}
|
||||
|
||||
function instanceOfEcdsaSignature(object) {
|
||||
return typeof object === "object" && "r" in object && "s" in object;
|
||||
}
|
||||
|
||||
function ES256KSignerAlg(recoverable) {
|
||||
return async function sign(payload, signer) {
|
||||
const signature = await signer(payload);
|
||||
if (instanceOfEcdsaSignature(signature)) {
|
||||
return toJose(signature, recoverable);
|
||||
} else {
|
||||
if (
|
||||
recoverable &&
|
||||
typeof fromJose(signature).recoveryParam === "undefined"
|
||||
) {
|
||||
throw new Error(
|
||||
`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`,
|
||||
);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const u8a = { toString, fromString };
|
||||
function leftpad(data, size = 64) {
|
||||
if (data.length === size) return data;
|
||||
return "0".repeat(size - data.length) + data;
|
||||
}
|
||||
|
||||
function sha256(payload) {
|
||||
const data = typeof payload === 'string' ? u8a.fromString(payload) : payload;
|
||||
return generateSHA256Hash(data);
|
||||
async function SimpleSigner(hexPrivateKey) {
|
||||
const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true);
|
||||
return async (data) => {
|
||||
const signature = await signer(data);
|
||||
return fromJose(signature);
|
||||
};
|
||||
}
|
||||
|
||||
function hexToBytes(s, minLength) {
|
||||
let input = s.startsWith("0x") ? s.substring(2) : s;
|
||||
|
||||
if (input.length % 2 !== 0) {
|
||||
input = `0${input}`;
|
||||
}
|
||||
|
||||
if (minLength) {
|
||||
const paddedLength = Math.max(input.length, minLength * 2);
|
||||
input = input.padStart(paddedLength, "00");
|
||||
}
|
||||
|
||||
return u8a.fromString(input.toLowerCase(), "base16");
|
||||
}
|
||||
|
||||
function ES256KSigner(privateKey, recoverable = false) {
|
||||
const privateKeyBytes = privateKey;
|
||||
if (privateKeyBytes.length !== 32) {
|
||||
throw new Error(
|
||||
`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
return async function (data) {
|
||||
const signature = nobleCurves.secp256k1.sign(sha256(data), privateKeyBytes);
|
||||
console.error(signature);
|
||||
return toJose(
|
||||
{
|
||||
r: leftpad(signature.r.toString(16)),
|
||||
s: leftpad(signature.s.toString(16)),
|
||||
recoveryParam: signature.recovery,
|
||||
},
|
||||
recoverable,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function toJose(signature, recoverable) {
|
||||
const { r, s, recoveryParam } = signature;
|
||||
const jose = new Uint8Array(recoverable ? 65 : 64);
|
||||
jose.set(u8a.fromString(r, "base16"), 0);
|
||||
jose.set(u8a.fromString(s, "base16"), 32);
|
||||
|
||||
if (recoverable) {
|
||||
if (typeof recoveryParam === "undefined") {
|
||||
throw new Error("Signer did not return a recoveryParam");
|
||||
}
|
||||
jose[64] = recoveryParam;
|
||||
}
|
||||
return bytesToBase64url(jose);
|
||||
}
|
||||
|
||||
function bytesToBase64url(b) {
|
||||
return u8a.toString(b, "base64url");
|
||||
}
|
||||
|
||||
async function accessToken(identifier) {
|
||||
const did = identifier['did'];
|
||||
const privateKeyHex = identifier['keys'][0]['privateKeyHex'];
|
||||
function base64ToBytes(s) {
|
||||
const inputBase64Url = s
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
return u8a.fromString(inputBase64Url, "base64url");
|
||||
}
|
||||
|
||||
const signer = await SimpleSigner(privateKeyHex);
|
||||
function bytesToHex(b) {
|
||||
return u8a.toString(b, "base16");
|
||||
}
|
||||
|
||||
const nowEpoch = Math.floor(Date.now() / 1000);
|
||||
const endEpoch = nowEpoch + 60; // add one minute
|
||||
|
||||
const tokenPayload = { exp: endEpoch, iat: nowEpoch, iss: did };
|
||||
const alg = undefined; // defaults to 'ES256K', more standardized but harder to verify vs ES256K-R
|
||||
const jwt = await createJWT(tokenPayload, {
|
||||
alg,
|
||||
issuer: did,
|
||||
signer,
|
||||
});
|
||||
console.error(jwt);
|
||||
return jwt;
|
||||
}
|
||||
|
||||
|
||||
async function createJWT(payload, options, header = {}) {
|
||||
const { issuer, signer, alg, expiresIn, canonicalize } = options;
|
||||
|
||||
if (!signer) throw new Error('missing_signer: No Signer functionality has been configured');
|
||||
if (!issuer) throw new Error('missing_issuer: No issuing DID has been configured');
|
||||
if (!header.typ) header.typ = 'JWT';
|
||||
if (!header.alg) header.alg = alg;
|
||||
|
||||
const timestamps = {
|
||||
iat: Math.floor(Date.now() / 1000),
|
||||
exp: undefined,
|
||||
};
|
||||
|
||||
if (expiresIn) {
|
||||
if (typeof expiresIn === 'number') {
|
||||
timestamps.exp = (payload.nbf || timestamps.iat) + Math.floor(expiresIn);
|
||||
} else {
|
||||
throw new Error('invalid_argument: JWT expiresIn is not a number');
|
||||
}
|
||||
}
|
||||
|
||||
const fullPayload = { ...timestamps, ...payload, iss: issuer };
|
||||
return createJWS(fullPayload, signer, header, { canonicalize });
|
||||
}
|
||||
|
||||
|
||||
const defaultAlg = 'ES256K'
|
||||
|
||||
|
||||
async function createJWS(payload, signer, header = {}, options = {}) {
|
||||
if (!header.alg) header.alg = defaultAlg;
|
||||
const encodedPayload = typeof payload === 'string' ? payload : encodeSection(payload, options.canonicalize);
|
||||
const signingInput = [encodeSection(header, options.canonicalize), encodedPayload].join('.');
|
||||
|
||||
const jwtSigner = ES256KSignerAlg(false);
|
||||
const signature = await jwtSigner(signingInput, signer);
|
||||
|
||||
// JWS Compact Serialization
|
||||
// https://www.rfc-editor.org/rfc/rfc7515#section-7.1
|
||||
return [signingInput, signature].join('.');
|
||||
}
|
||||
|
||||
function canonicalizeData (object) {
|
||||
if (typeof object === 'number' && isNaN(object)) {
|
||||
throw new Error('NaN is not allowed');
|
||||
}
|
||||
|
||||
if (typeof object === 'number' && !isFinite(object)) {
|
||||
throw new Error('Infinity is not allowed');
|
||||
}
|
||||
|
||||
if (object === null || typeof object !== 'object') {
|
||||
return JSON.stringify(object);
|
||||
}
|
||||
|
||||
if (object.toJSON instanceof Function) {
|
||||
return serialize(object.toJSON());
|
||||
}
|
||||
|
||||
if (Array.isArray(object)) {
|
||||
const values = object.reduce((t, cv, ci) => {
|
||||
const comma = ci === 0 ? '' : ',';
|
||||
const value = cv === undefined || typeof cv === 'symbol' ? null : cv;
|
||||
return `${t}${comma}${serialize(value)}`;
|
||||
}, '');
|
||||
return `[${values}]`;
|
||||
}
|
||||
|
||||
const values = Object.keys(object).sort().reduce((t, cv) => {
|
||||
if (object[cv] === undefined ||
|
||||
typeof object[cv] === 'symbol') {
|
||||
return t;
|
||||
}
|
||||
const comma = t.length === 0 ? '' : ',';
|
||||
return `${t}${comma}${serialize(cv)}:${serialize(object[cv])}`;
|
||||
}, '');
|
||||
return `{${values}}`;
|
||||
};
|
||||
|
||||
function encodeSection(data, shouldCanonicalize = false) {
|
||||
if (shouldCanonicalize) {
|
||||
return encodeBase64url(canonicalizeData(data));
|
||||
} else {
|
||||
return encodeBase64url(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function encodeBase64url(s) {
|
||||
return bytesToBase64url(u8a.fromString(s))
|
||||
}
|
||||
|
||||
function instanceOfEcdsaSignature(object) {
|
||||
return typeof object === 'object' && 'r' in object && 's' in object;
|
||||
}
|
||||
|
||||
function ES256KSignerAlg(recoverable) {
|
||||
return async function sign(payload, signer) {
|
||||
const signature = await signer(payload);
|
||||
if (instanceOfEcdsaSignature(signature)) {
|
||||
return toJose(signature, recoverable);
|
||||
} else {
|
||||
if (recoverable && typeof fromJose(signature).recoveryParam === 'undefined') {
|
||||
throw new Error(`not_supported: ES256K-R not supported when signer doesn't provide a recovery param`);
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function leftpad(data, size = 64) {
|
||||
if (data.length === size) return data;
|
||||
return '0'.repeat(size - data.length) + data;
|
||||
}
|
||||
|
||||
|
||||
async function SimpleSigner(hexPrivateKey) {
|
||||
const signer = await ES256KSigner(hexToBytes(hexPrivateKey), true);
|
||||
return async (data) => {
|
||||
const signature = (await signer(data));
|
||||
return fromJose(signature);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function hexToBytes(s, minLength) {
|
||||
let input = s.startsWith('0x') ? s.substring(2) : s;
|
||||
|
||||
if (input.length % 2 !== 0) {
|
||||
input = `0${input}`;
|
||||
}
|
||||
|
||||
if (minLength) {
|
||||
const paddedLength = Math.max(input.length, minLength * 2);
|
||||
input = input.padStart(paddedLength, '00');
|
||||
}
|
||||
|
||||
return u8a.fromString(input.toLowerCase(), 'base16');
|
||||
}
|
||||
|
||||
|
||||
function ES256KSigner(privateKey, recoverable = false) {
|
||||
const privateKeyBytes = privateKey;
|
||||
if (privateKeyBytes.length !== 32) {
|
||||
throw new Error(`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`);
|
||||
}
|
||||
|
||||
return async function(data) {
|
||||
const hash = await sha256(data);
|
||||
const signature = nobleCurves.secp256k1.sign(hash, privateKeyBytes);
|
||||
|
||||
return toJose({
|
||||
r: leftpad(signature.r.toString(16)),
|
||||
s: leftpad(signature.s.toString(16)),
|
||||
recoveryParam: signature.recovery,
|
||||
}, recoverable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toJose(signature, recoverable) {
|
||||
const { r, s, recoveryParam } = signature;
|
||||
const jose = new Uint8Array(recoverable ? 65 : 64);
|
||||
jose.set(u8a.fromString(r, 'base16'), 0);
|
||||
jose.set(u8a.fromString(s, 'base16'), 32);
|
||||
|
||||
if (recoverable) {
|
||||
if (typeof recoveryParam === 'undefined') {
|
||||
throw new Error('Signer did not return a recoveryParam');
|
||||
}
|
||||
jose[64] = recoveryParam;
|
||||
}
|
||||
return bytesToBase64url(jose);
|
||||
}
|
||||
|
||||
|
||||
function bytesToBase64url(b) {
|
||||
return u8a.toString(b, 'base64url');
|
||||
}
|
||||
|
||||
function base64ToBytes(s) {
|
||||
const inputBase64Url = s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
|
||||
return u8a.fromString(inputBase64Url, 'base64url')
|
||||
}
|
||||
|
||||
function bytesToHex(b) {
|
||||
return u8a.toString(b, 'base16')
|
||||
}
|
||||
|
||||
function fromJose(signature) {
|
||||
const signatureBytes = base64ToBytes(signature);
|
||||
if (signatureBytes.length < 64 || signatureBytes.length > 65) {
|
||||
throw new TypeError(`Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`,);
|
||||
}
|
||||
const r = bytesToHex(signatureBytes.slice(0, 32));
|
||||
const s = bytesToHex(signatureBytes.slice(32, 64));
|
||||
const recoveryParam = signatureBytes.length === 65 ? signatureBytes[64] : undefined;
|
||||
|
||||
return { r, s, recoveryParam };
|
||||
}
|
||||
function fromJose(signature) {
|
||||
const signatureBytes = base64ToBytes(signature);
|
||||
if (signatureBytes.length < 64 || signatureBytes.length > 65) {
|
||||
throw new TypeError(
|
||||
`Wrong size for signature. Expected 64 or 65 bytes, but got ${signatureBytes.length}`,
|
||||
);
|
||||
}
|
||||
const r = bytesToHex(signatureBytes.slice(0, 32));
|
||||
const s = bytesToHex(signatureBytes.slice(32, 64));
|
||||
const recoveryParam =
|
||||
signatureBytes.length === 65 ? signatureBytes[64] : undefined;
|
||||
|
||||
return { r, s, recoveryParam };
|
||||
}
|
||||
|
||||
function validateBase64(s) {
|
||||
if (
|
||||
@@ -436,20 +442,23 @@ async function getNotificationCount() {
|
||||
const decrypted = self.secretbox.open(message, nonce, secretUint8Array);
|
||||
|
||||
const msg = decoder.decode(decrypted);
|
||||
const identifier = JSON.parse(JSON.parse(msg));
|
||||
const identifier = JSON.parse(JSON.parse(msg));
|
||||
|
||||
console.log(identifier);
|
||||
console.log(identifier);
|
||||
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
headers["Authorization"] = "Bearer " + await accessToken(identifier);
|
||||
headers["Authorization"] = "Bearer " + (await accessToken(identifier));
|
||||
|
||||
let response = await fetch("https://test-api.endorser.ch/api/v2/report/claims", {
|
||||
method: 'GET',
|
||||
let response = await fetch(
|
||||
"https://test-api.endorser.ch/api/v2/report/claims",
|
||||
{
|
||||
method: "GET",
|
||||
headers: headers,
|
||||
});
|
||||
},
|
||||
);
|
||||
console.error(did, response.status);
|
||||
console.error(await response.json());
|
||||
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
(function () {
|
||||
randomBytes = (length) => self.crypto.getRandomValues(new Uint8Array(length));
|
||||
self.Secp256k1 = exports = {};
|
||||
|
||||
function uint256(x, base) {
|
||||
return new BN(x, base);
|
||||
}
|
||||
|
||||
function rnd(P) {
|
||||
return uint256(randomBytes(32)).umod(P); //TODO red
|
||||
}
|
||||
|
||||
const A = uint256(0);
|
||||
const B = uint256(7);
|
||||
const GX = uint256(
|
||||
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
|
||||
16,
|
||||
);
|
||||
const GY = uint256(
|
||||
"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
|
||||
16,
|
||||
);
|
||||
const P = uint256(
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
|
||||
16,
|
||||
);
|
||||
const N = uint256(
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
|
||||
16,
|
||||
);
|
||||
//const RED = BN.red(P)
|
||||
const _0 = uint256(0);
|
||||
const _1 = uint256(1);
|
||||
|
||||
// function for elliptic curve multiplication in jacobian coordinates using Double-and-add method
|
||||
function ecmul(_p, _d) {
|
||||
let R = [_0, _0, _0];
|
||||
|
||||
//return (0,0) if d=0 or (x1,y1)=(0,0)
|
||||
if (_d == 0 || (_p[0] == 0 && _p[1] == 0)) {
|
||||
return R;
|
||||
}
|
||||
let T = [
|
||||
_p[0], //x-coordinate temp
|
||||
_p[1], //y-coordinate temp
|
||||
_p[2], //z-coordinate temp
|
||||
];
|
||||
|
||||
const d = _d.clone();
|
||||
while (d != 0) {
|
||||
if (d.testn(0)) {
|
||||
//if last bit is 1 add T to result
|
||||
R = ecadd(T, R);
|
||||
}
|
||||
T = ecdouble(T); //double temporary coordinates
|
||||
d.iushrn(1); //"cut off" last bit
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
|
||||
function mulmod(a, b, P) {
|
||||
return a.mul(b).umod(P); //TODO red
|
||||
}
|
||||
|
||||
function addmod(a, b, P) {
|
||||
return a.add(b).umod(P); //TODO red
|
||||
}
|
||||
|
||||
function invmod(a, P) {
|
||||
return a.invm(P); //TODO redq
|
||||
}
|
||||
|
||||
function mulG(k) {
|
||||
const GinJ = AtoJ(GX, GY);
|
||||
const PUBinJ = ecmul(GinJ, k);
|
||||
return JtoA(PUBinJ);
|
||||
}
|
||||
|
||||
function assert(cond, msg) {
|
||||
if (!cond) {
|
||||
throw Error("assertion failed: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
function ecsign(d, z) {
|
||||
assert(d != 0, "d must not be 0");
|
||||
assert(z != 0, "z must not be 0");
|
||||
while (true) {
|
||||
const k = rnd(P);
|
||||
const R = mulG(k);
|
||||
if (R[0] == 0) continue;
|
||||
const s = mulmod(invmod(k, N), addmod(z, mulmod(R[0], d, N), N), N);
|
||||
if (s == 0) continue;
|
||||
//FIXME: why do I need this
|
||||
if (s.testn(255)) continue;
|
||||
return { r: toHex(R[0]), s: toHex(s), v: R[1].testn(0) ? 1 : 0 };
|
||||
}
|
||||
}
|
||||
|
||||
function JtoA(p) {
|
||||
const zInv = invmod(p[2], P);
|
||||
const zInv2 = mulmod(zInv, zInv, P);
|
||||
return [mulmod(p[0], zInv2, P), mulmod(p[1], mulmod(zInv, zInv2, P), P)];
|
||||
}
|
||||
|
||||
//point doubling for elliptic curve in jacobian coordinates
|
||||
//formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
|
||||
function ecdouble(_p) {
|
||||
if (_p[1] == 0) {
|
||||
//return point at infinity
|
||||
return [_1, _1, _0];
|
||||
}
|
||||
|
||||
const z2 = mulmod(_p[2], _p[2], P);
|
||||
const m = addmod(
|
||||
mulmod(A, mulmod(z2, z2, P), P),
|
||||
mulmod(uint256(3), mulmod(_p[0], _p[0], P), P),
|
||||
P,
|
||||
);
|
||||
const y2 = mulmod(_p[1], _p[1], P);
|
||||
const s = mulmod(uint256(4), mulmod(_p[0], y2, P), P);
|
||||
|
||||
const x = addmod(mulmod(m, m, P), negmod(mulmod(s, uint256(2), P), P), P);
|
||||
return [
|
||||
x,
|
||||
addmod(
|
||||
mulmod(m, addmod(s, negmod(x, P), P), P),
|
||||
negmod(mulmod(uint256(8), mulmod(y2, y2, P), P), P),
|
||||
P,
|
||||
),
|
||||
mulmod(uint256(2), mulmod(_p[1], _p[2], P), P),
|
||||
];
|
||||
}
|
||||
|
||||
function negmod(a, P) {
|
||||
return P.sub(a);
|
||||
}
|
||||
|
||||
// point addition for elliptic curve in jacobian coordinates
|
||||
// formula from https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
|
||||
function ecadd(_p, _q) {
|
||||
if (_q[0] == 0 && _q[1] == 0 && _q[2] == 0) {
|
||||
return _p;
|
||||
}
|
||||
|
||||
let z2 = mulmod(_q[2], _q[2], P);
|
||||
const u1 = mulmod(_p[0], z2, P);
|
||||
const s1 = mulmod(_p[1], mulmod(z2, _q[2], P), P);
|
||||
z2 = mulmod(_p[2], _p[2], P);
|
||||
let u2 = mulmod(_q[0], z2, P);
|
||||
let s2 = mulmod(_q[1], mulmod(z2, _p[2], P), P);
|
||||
|
||||
if (u1.eq(u2)) {
|
||||
if (!s1.eq(s2)) {
|
||||
//return point at infinity
|
||||
return [_1, _1, _0];
|
||||
} else {
|
||||
return ecdouble(_p);
|
||||
}
|
||||
}
|
||||
|
||||
u2 = addmod(u2, negmod(u1, P), P);
|
||||
z2 = mulmod(u2, u2, P);
|
||||
const t2 = mulmod(u1, z2, P);
|
||||
z2 = mulmod(u2, z2, P);
|
||||
s2 = addmod(s2, negmod(s1, P), P);
|
||||
const x = addmod(
|
||||
addmod(mulmod(s2, s2, P), negmod(z2, P), P),
|
||||
negmod(mulmod(uint256(2), t2, P), P),
|
||||
P,
|
||||
);
|
||||
return [
|
||||
x,
|
||||
addmod(
|
||||
mulmod(s2, addmod(t2, negmod(x, P), P), P),
|
||||
negmod(mulmod(s1, z2, P), P),
|
||||
P,
|
||||
),
|
||||
mulmod(u2, mulmod(_p[2], _q[2], P), P),
|
||||
];
|
||||
}
|
||||
|
||||
function AtoJ(x, y) {
|
||||
return [uint256(x), uint256(y), _1];
|
||||
}
|
||||
|
||||
function isValidPoint(x, y) {
|
||||
const yy = addmod(mulmod(mulmod(x, x, P), x, P), B, P);
|
||||
return yy.eq(mulmod(y, y, P));
|
||||
}
|
||||
|
||||
function toHex(bn) {
|
||||
return (
|
||||
"00000000000000000000000000000000000000000000000000000000000000000000000000000000" +
|
||||
bn.toString(16)
|
||||
).slice(-64);
|
||||
}
|
||||
|
||||
function decompressKey(x, yBit) {
|
||||
let redP = BN.red("k256");
|
||||
x = x.toRed(redP);
|
||||
const y = x.redMul(x).redMul(x).redAdd(B.toRed(redP)).redSqrt();
|
||||
const sign = y.testn(0);
|
||||
return (sign != yBit ? y.redNeg() : y).fromRed();
|
||||
}
|
||||
|
||||
function generatePublicKeyFromPrivateKeyData(pk) {
|
||||
const p = mulG(pk);
|
||||
return { x: toHex(p[0]), y: toHex(p[1]) };
|
||||
}
|
||||
|
||||
function ecrecover(recId, sigr, sigs, message) {
|
||||
assert(recId >= 0 && recId <= 3, "recId must be 0..3");
|
||||
assert(sigr != 0, "sigr must not be 0");
|
||||
assert(sigs != 0, "sigs must not be 0");
|
||||
// 1.0 For j from 0 to h (h == recId here and the loop is outside this function)
|
||||
// 1.1 Let x = r + jn
|
||||
const x = addmod(uint256(sigr), P.muln(recId >> 1), P);
|
||||
// 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine
|
||||
// specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉.
|
||||
// 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the
|
||||
// conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then
|
||||
// do another iteration of Step 1.
|
||||
//
|
||||
// More concisely, what these points mean is to use X as a compressed public key.
|
||||
if (x.gte(P)) {
|
||||
// Cannot have point co-ordinates larger than this as everything takes place modulo Q.
|
||||
return null;
|
||||
}
|
||||
// Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities.
|
||||
// So it's encoded in the recId.
|
||||
const y = decompressKey(x, (recId & 1) == 1);
|
||||
// 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility).
|
||||
// if (!R.mul(N).isInfinity())
|
||||
// return null
|
||||
// 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification.
|
||||
const e = uint256(message);
|
||||
// 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId)
|
||||
// 1.6.1. Compute a candidate public key as:
|
||||
// Q = mi(r) * (sR - eG)
|
||||
//
|
||||
// Where mi(x) is the modular multiplicative inverse. We transform this into the following:
|
||||
// Q = (mi(r) * s ** R) + (mi(r) * -e ** G)
|
||||
// Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation
|
||||
// ** is point multiplication and + is point addition (the EC group operator).
|
||||
//
|
||||
// We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive
|
||||
// inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8.
|
||||
const eNeg = negmod(e, N);
|
||||
const rInv = invmod(sigr, N);
|
||||
const srInv = mulmod(rInv, sigs, N);
|
||||
const eNegrInv = mulmod(rInv, eNeg, N);
|
||||
const R = AtoJ(x, y);
|
||||
const G = AtoJ(GX, GY);
|
||||
const qinJ = ecadd(ecmul(G, eNegrInv), ecmul(R, srInv));
|
||||
const p = JtoA(qinJ);
|
||||
return { x: toHex(p[0]), y: toHex(p[1]) };
|
||||
}
|
||||
|
||||
function ecverify(Qx, Qy, sigr, sigs, z) {
|
||||
if (sigs == 0 || sigr == 0) {
|
||||
return false;
|
||||
}
|
||||
const w = invmod(sigs, N);
|
||||
const u1 = mulmod(z, w, N);
|
||||
const u2 = mulmod(sigr, w, N);
|
||||
const Q = AtoJ(Qx, Qy);
|
||||
const G = AtoJ(GX, GY);
|
||||
const RinJ = ecadd(ecmul(G, u1), ecmul(Q, u2));
|
||||
const r = JtoA(RinJ);
|
||||
return sigr.eq(r[0]);
|
||||
}
|
||||
|
||||
exports.uint256 = uint256;
|
||||
exports.ecsign = ecsign;
|
||||
exports.ecrecover = ecrecover;
|
||||
exports.generatePublicKeyFromPrivateKeyData =
|
||||
generatePublicKeyFromPrivateKeyData;
|
||||
exports.decompressKey = decompressKey;
|
||||
exports.isValidPoint = isValidPoint;
|
||||
exports.ecverify = ecverify;
|
||||
})();
|
||||
3542
sw_scripts/sw-bn.js
3542
sw_scripts/sw-bn.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user