Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

verify assets ownership & issuance, improve autopeering, current epoch checkpoint #5

Merged
merged 2 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions .github/badges/test.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,302 changes: 651 additions & 651 deletions src/checkpoint.js

Large diffs are not rendered by default.

240 changes: 232 additions & 8 deletions src/client.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ export const QUORUM = Math.floor((2 / 3) * NUMBER_OF_COMPUTORS) + 1;

export const SPECTRUM_DEPTH = 24;

export const ASSETS_DEPTH = 24;

export const ASSET_TYPES = {
EMPTY: 0,
ISSUANCE: 1,
OWNERSHIP: 2,
POSSESSION: 3,
};

export const TARGET_TICK_DURATION = 3000;
export const MAX_NUMBER_OF_TICKS_PER_EPOCH = (((((60 * 60 * 24 * 7) / (TARGET_TICK_DURATION / 1000)) + NUMBER_OF_COMPUTORS - 1) / NUMBER_OF_COMPUTORS) * NUMBER_OF_COMPUTORS);

Expand All @@ -69,3 +78,5 @@ export const MAX_AMOUNT = ISSUANCE_RATE * 1000n;
export const MAX_NUMBER_OF_CONTRACTS = 1024;

export const TICK_TRANSACTIONS_PUBLICATION_OFFSET = 2; // must be only 2.

export const CONTRACTS = ['', 'Qx'];
249 changes: 137 additions & 112 deletions src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,140 +57,140 @@ export const LE = true;
export const ALPHABET = 'abcdefghijklmnopqrstuvwxyz';

export const bytesToBigUint64 = function (bytes) {
const view = new DataView(bytes.buffer, bytes.byteOffset);
return view.getBigUint64(0, true);
const view = new DataView(bytes.buffer, bytes.byteOffset);
return view.getBigUint64(0, true);
};

export const bigUint64ToBytes = function (value) {
const bytes = new Uint8Array(8);
const view = new DataView(bytes.buffer, bytes.byteOffset);
view.setBigUint64(0, value, true);
return bytes;
const bytes = new Uint8Array(8);
const view = new DataView(bytes.buffer, bytes.byteOffset);
view.setBigUint64(0, value, true);
return bytes;
};

export const bigUint64ToString = function (value) {
let s = '';
let s = '';

for (let j = 0; j < 14; j++) {
s += String.fromCharCode(Number(value % 26n + BigInt('A'.charCodeAt(0))));
value /= 26n;
}
for (let j = 0; j < 14; j++) {
s += String.fromCharCode(Number(value % 26n + BigInt('A'.charCodeAt(0))));
value /= 26n;
}

return s.toLocaleLowerCase();
return s.toLocaleLowerCase();
};

export const NULL_BIG_UINT64_STRING = bigUint64ToBytes(0n);

export const stringToBigUint64 = function (s) {
s = s.toUpperCase();
s = s.toUpperCase();

let value = 0n;
let value = 0n;

for (let j = 14; j-- > 0;) {
value *= 26n + BigInt(s.charCodeAt(j)) - BigInt('A'.charCodeAt(0));
}
for (let j = 14; j-- > 0;) {
value *= 26n + BigInt(s.charCodeAt(j)) - BigInt('A'.charCodeAt(0));
}

return value;
return value;
};

export const bytes32ToString = function (bytes) {
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}
if (bytes.byteLength !== 32) {
throw new RangeError('Invalid byte length.');
}

const view = new DataView(bytes.buffer, bytes.byteOffset);
let s = '';

for (let i = 0; i < 4; i++){
let fragment = view.getBigUint64(i << 3, LE);
for (let j = 0; j < 14; j++) {
s += String.fromCharCode(Number(fragment % 26n + BigInt('A'.charCodeAt(0))));
fragment /= 26n;
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}
}
if (bytes.byteLength !== 32) {
throw new RangeError('Invalid byte length.');
}

const view = new DataView(bytes.buffer, bytes.byteOffset);
let s = '';

return s.toLowerCase();
for (let i = 0; i < 4; i++){
let fragment = view.getBigUint64(i << 3, LE);
for (let j = 0; j < 14; j++) {
s += String.fromCharCode(Number(fragment % 26n + BigInt('A'.charCodeAt(0))));
fragment /= 26n;
}
}

return s.toLowerCase();
};

export const stringToBytes32 = function (s) {
if (new RegExp(`^[a-z]{${4 * 14}}$`).test(s) === false) {
throw new Error(`Invalid string. Expected ${4 * 14} lowercase latin chars.`);
}
if (new RegExp(`^[a-z]{${4 * 14}}$`).test(s) === false) {
throw new Error(`Invalid string. Expected ${4 * 14} lowercase latin chars.`);
}

s = s.toUpperCase();
s = s.toUpperCase();

const bytes = new Uint8Array(32);
const view = new DataView(bytes.buffer, bytes.byteOffset);
const bytes = new Uint8Array(32);
const view = new DataView(bytes.buffer, bytes.byteOffset);

for (let i = 0; i < 4; i++) {
view.setBigUint64(i * 8, 0n, LE);
for (let j = 14; j-- > 0;) {
view.setBigUint64(i * 8, view.getBigUint64(i * 8, LE) * 26n + BigInt(s.charCodeAt(i * 14 + j)) - BigInt('A'.charCodeAt(0)), LE);
for (let i = 0; i < 4; i++) {
view.setBigUint64(i * 8, 0n, LE);
for (let j = 14; j-- > 0;) {
view.setBigUint64(i * 8, view.getBigUint64(i * 8, LE) * 26n + BigInt(s.charCodeAt(i * 14 + j)) - BigInt('A'.charCodeAt(0)), LE);
}
}
}

return bytes;
return bytes;
};

export const bytes64ToString = function (bytes) {
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}
if (bytes.byteLength !== 64) {
throw new RangeError('Invalid byte length.');
}

return bytes32ToString(bytes.subarray(0, 32)) + bytes32ToString(bytes.subarray(32, 64));
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}
if (bytes.byteLength !== 64) {
throw new RangeError('Invalid byte length.');
}

return bytes32ToString(bytes.subarray(0, 32)) + bytes32ToString(bytes.subarray(32, 64));
}

export const stringToBytes64 = function (s) {
if (new RegExp(`^[a-z]{${4 * 14 * 2}}$`).test(s) === false) {
throw new Error(`Invalid string. Expected ${4 * 14 * 2} lowercase latin chars.`);
}

const bytes = new Uint8Array(64);
bytes.set(stringToBytes32(s.slice(0, 4 * 14)), 0);
bytes.set(stringToBytes32(s.slice(4 * 14, 4 * 14 * 2)), 32);
return bytes;
}
if (new RegExp(`^[a-z]{${4 * 14 * 2}}$`).test(s) === false) {
throw new Error(`Invalid string. Expected ${4 * 14 * 2} lowercase latin chars.`);
}

const bytes = new Uint8Array(64);
bytes.set(stringToBytes32(s.slice(0, 4 * 14)), 0);
bytes.set(stringToBytes32(s.slice(4 * 14, 4 * 14 * 2)), 32);
return bytes;
}

const checksum = async function (publicKey) {
const buffer = new Uint8Array(4);
await crypto.K12(publicKey.slice(), buffer, 4);
const checksum = async function (publicKey) {
const buffer = new Uint8Array(4);
await crypto.K12(publicKey.slice(), buffer, 4);

let checksum = new DataView(buffer.buffer, buffer.byteOffset).getUint32(0, LE) & 0x3FFFF;
let s = '';
let checksum = new DataView(buffer.buffer, buffer.byteOffset).getUint32(0, LE) & 0x3FFFF;
let s = '';

for (let i = 0; i < 4; i++) {
s += String.fromCharCode(checksum % 26 + 'A'.charCodeAt(0));
checksum /= 26;
}
for (let i = 0; i < 4; i++) {
s += String.fromCharCode(checksum % 26 + 'A'.charCodeAt(0));
checksum /= 26;
}

return s;
return s;
};

export const bytesToId = async function (bytes) {
return bytes32ToString(bytes).toUpperCase() + (await checksum(bytes));
return bytes32ToString(bytes).toUpperCase() + (await checksum(bytes));
};

export const idToBytes = async function (s) {
if (new RegExp(`^[A-Z]{${60}}$`).test(s) === false) {
throw new Error('Invalid id. Expected 60 uppercase latin chars.');
}
if (new RegExp(`^[A-Z]{${60}}$`).test(s) === false) {
throw new Error('Invalid id. Expected 60 uppercase latin chars.');
}

const bytes = stringToBytes32(s.slice(0, 56).toLowerCase());
const bytes = stringToBytes32(s.slice(0, 56).toLowerCase());

if ((await checksum(bytes)) !== s.slice(56, 60)) {
throw new Error('Invalid checksum!');
}
if ((await checksum(bytes)) !== s.slice(56, 60)) {
throw new Error('Invalid checksum!');
}

return bytes;
return bytes;
};

export const NULL_ID_STRING = 'a'.repeat(60);
export const NULL_ID_STRING = bytesToId(new Uint8Array(crypto.PUBLIC_KEY_LENGTH).fill(0));

export const digestBytesToString = bytes32ToString;

Expand All @@ -202,38 +202,63 @@ const HEX_ALPHABET = '0123456789abcdef';
const SHIFTED_HEX_ALPHABET = 'abcdefghijklmnop';

export const shiftedHexToBytes = function (s) {
if (/[a-p]/.test(s) === false) {
throw new TypeError('Invalid shifted hex string.');
}

if (s.length % 2 !== 0) {
s = 'a' + s;
}

const bytes = new Uint8Array(s.length / 2);
for (let i = 0, j = 0; j < s.length; j += 2) {
bytes[i++] = parseInt(s.substr(j, 2).split('').map((char) => HEX_ALPHABET[SHIFTED_HEX_ALPHABET.indexOf(char)]).join(''), 16);
}
return bytes;
if (/[a-p]/.test(s) === false) {
throw new TypeError('Invalid shifted hex string.');
}

if (s.length % 2 !== 0) {
s = 'a' + s;
}

const bytes = new Uint8Array(s.length / 2);
for (let i = 0, j = 0; j < s.length; j += 2) {
bytes[i++] = parseInt(s.substr(j, 2).split('').map((char) => HEX_ALPHABET[SHIFTED_HEX_ALPHABET.indexOf(char)]).join(''), 16);
}
return bytes;
};

export const bytesToShiftedHex = function (bytes) {
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}

let s = '';
for (let i = 0; i < bytes.byteLength; i++) {
s += SHIFTED_HEX_CHARS[bytes[i] >> 4] + SHIFTED_HEX_CHARS[bytes[i] & 15];
}
return s;
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}

let s = '';
for (let i = 0; i < bytes.byteLength; i++) {
s += SHIFTED_HEX_CHARS[bytes[i] >> 4] + SHIFTED_HEX_CHARS[bytes[i] & 15];
}
return s;
};

export const stringToBytes = function (s) {
const bytes = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) {
bytes[i] = ALPHABET.indexOf(s[i].toLowerCase()) + 'A'.charCodeAt(0);
}
return bytes;
};

export const bytesToString = function (bytes) {
if (Object.prototype.toString.call(bytes) !== '[object Uint8Array]') {
throw new TypeError('Invalid bytes. Ecpected Uint8Array.');
}

let s = '';
for (let i = 0; i < bytes.length; i++) {
if ((bytes[i] - 'A'.charCodeAt(0)) >= ALPHABET.length) {
throw new RangeError('Invalid bytes. Expected bytes in [0, 25] range.');
}
if (bytes[i] >= 'A'.charCodeAt(0)) {
s += ALPHABET[Math.max(0, bytes[i] - 'A'.charCodeAt(0))].toUpperCase();
}
}
return s;
};

export const stringToSeedBytes = function (s) {
const bytes = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) {
bytes[i] = ALPHABET.indexOf(s[i]);
}
s = undefined;
return bytes;
const bytes = new Uint8Array(s.length);
for (let i = 0; i < s.length; i++) {
bytes[i] = ALPHABET.indexOf(s[i]);
}
s = undefined;
return bytes;
}
Loading