203 lines
7.4 KiB
TypeScript
203 lines
7.4 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { defaultTestCryptoProvider } from '@mtcute/test'
|
|
|
|
import { getPlatform } from '../platform.js'
|
|
import {
|
|
bigIntBitLength,
|
|
bigIntGcd,
|
|
bigIntModInv,
|
|
bigIntModPow,
|
|
bigIntToBuffer,
|
|
bufferToBigInt,
|
|
randomBigInt,
|
|
randomBigIntBits,
|
|
randomBigIntInRange,
|
|
twoMultiplicity,
|
|
} from './index.js'
|
|
|
|
const p = getPlatform()
|
|
|
|
describe('bigIntBitLength', () => {
|
|
it('should correctly calculate bit length', () => {
|
|
expect(bigIntBitLength(0n)).eq(0)
|
|
expect(bigIntBitLength(1n)).eq(1)
|
|
expect(bigIntBitLength(2n)).eq(2)
|
|
expect(bigIntBitLength(255n)).eq(8)
|
|
expect(bigIntBitLength(256n)).eq(9)
|
|
})
|
|
})
|
|
|
|
describe('bigIntToBuffer', () => {
|
|
it('should handle writing to BE', () => {
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 0, false)]).eql([0xa0, 0x26, 0xdc])
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 4, false)]).eql([0x00, 0xa0, 0x26, 0xdc])
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 8, false)]).eql([0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x26, 0xdc])
|
|
expect([...bigIntToBuffer(BigInt('3038102549'), 4, false)]).eql([0xb5, 0x15, 0xc4, 0x15])
|
|
expect([...bigIntToBuffer(BigInt('9341376580368336208'), 8, false)]).eql([
|
|
...p.hexDecode('81A33C81D2020550'),
|
|
])
|
|
})
|
|
|
|
it('should handle writing to LE', () => {
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 0, true)]).eql([0xdc, 0x26, 0xa0])
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 4, true)]).eql([0xdc, 0x26, 0xa0, 0x00])
|
|
expect([...bigIntToBuffer(BigInt('10495708'), 8, true)]).eql([0xdc, 0x26, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00])
|
|
expect([...bigIntToBuffer(BigInt('3038102549'), 4, true)]).eql([0x15, 0xc4, 0x15, 0xb5])
|
|
expect([...bigIntToBuffer(BigInt('9341376580368336208'), 8, true)]).eql([
|
|
...p.hexDecode('81A33C81D2020550').reverse(),
|
|
])
|
|
})
|
|
|
|
it('should handle large integers', () => {
|
|
const buf = p.hexDecode(
|
|
'1a981ce8bf86bf4a1bd79c2ef829914172f8d0e54cb7ad807552d56977e1c946872e2c7bd77052be30e7e9a7a35c4feff848a25759f5f2f5b0e96538',
|
|
)
|
|
const num = BigInt(
|
|
'0x1a981ce8bf86bf4a1bd79c2ef829914172f8d0e54cb7ad807552d56977e1c946872e2c7bd77052be30e7e9a7a35c4feff848a25759f5f2f5b0e96538',
|
|
)
|
|
|
|
expect([...bigIntToBuffer(num, 0, false)]).eql([...buf])
|
|
expect([...bigIntToBuffer(num, 0, true)]).eql([...buf.reverse()])
|
|
})
|
|
})
|
|
|
|
describe('bufferToBigInt', () => {
|
|
it('should handle reading BE', () => {
|
|
expect(bufferToBigInt(new Uint8Array([0xa0, 0x26, 0xdc]), false).toString()).eq('10495708')
|
|
expect(bufferToBigInt(new Uint8Array([0x00, 0xa0, 0x26, 0xdc]), false).toString()).eq('10495708')
|
|
expect(bufferToBigInt(new Uint8Array([0xb5, 0x15, 0xc4, 0x15]), false).toString()).eq('3038102549')
|
|
})
|
|
|
|
it('should handle reading LE', () => {
|
|
expect(bufferToBigInt(new Uint8Array([0xdc, 0x26, 0xa0]), true).toString()).eq('10495708')
|
|
expect(bufferToBigInt(new Uint8Array([0xdc, 0x26, 0xa0, 0x00]), true).toString()).eq('10495708')
|
|
expect(bufferToBigInt(new Uint8Array([0x15, 0xc4, 0x15, 0xb5]), true).toString()).eq('3038102549')
|
|
})
|
|
|
|
it('should handle large integers', () => {
|
|
const buf = p.hexDecode(
|
|
'1a981ce8bf86bf4a1bd79c2ef829914172f8d0e54cb7ad807552d56977e1c946872e2c7bd77052be30e7e9a7a35c4feff848a25759f5f2f5b0e96538',
|
|
)
|
|
const num = BigInt(
|
|
'0x1a981ce8bf86bf4a1bd79c2ef829914172f8d0e54cb7ad807552d56977e1c946872e2c7bd77052be30e7e9a7a35c4feff848a25759f5f2f5b0e96538',
|
|
)
|
|
|
|
expect(bufferToBigInt(buf, false).toString()).eq(num.toString())
|
|
expect(bufferToBigInt(buf.reverse(), true).toString()).eq(num.toString())
|
|
})
|
|
})
|
|
|
|
describe('randomBigInt', async () => {
|
|
const c = await defaultTestCryptoProvider()
|
|
|
|
it('should return a random bigint', () => {
|
|
const a = randomBigInt(c, 32)
|
|
const b = randomBigInt(c, 32)
|
|
|
|
expect(a).not.toEqual(b)
|
|
})
|
|
|
|
it('should return a random bigint up to specified byte length', () => {
|
|
const a = randomBigInt(c, 32)
|
|
const b = randomBigInt(c, 64)
|
|
|
|
expect(bigIntBitLength(a)).toBeLessThanOrEqual(32 * 8)
|
|
expect(bigIntBitLength(b)).toBeLessThanOrEqual(64 * 8)
|
|
})
|
|
})
|
|
|
|
describe('randomBigIntBits', async () => {
|
|
const c = await defaultTestCryptoProvider()
|
|
|
|
it('should return a random bigint', () => {
|
|
const a = randomBigIntBits(c, 32)
|
|
const b = randomBigIntBits(c, 32)
|
|
|
|
expect(a).not.toEqual(b)
|
|
})
|
|
|
|
it('should return a random bigint up to specified bit length', () => {
|
|
const a = randomBigIntBits(c, 32)
|
|
const b = randomBigIntBits(c, 64)
|
|
|
|
expect(bigIntBitLength(a)).toBeLessThanOrEqual(32)
|
|
expect(bigIntBitLength(b)).toBeLessThanOrEqual(64)
|
|
})
|
|
})
|
|
|
|
describe('randomBigIntInRange', async () => {
|
|
const c = await defaultTestCryptoProvider()
|
|
|
|
it('should return a random bigint', () => {
|
|
const a = randomBigIntInRange(c, 10000n)
|
|
const b = randomBigIntInRange(c, 10000n)
|
|
|
|
expect(a).not.toEqual(b)
|
|
})
|
|
|
|
it('should return a bigint within a given range', () => {
|
|
const a = randomBigIntInRange(c, 200n, 100n)
|
|
|
|
expect(a).toBeGreaterThanOrEqual(100n)
|
|
expect(a).toBeLessThan(200n)
|
|
})
|
|
})
|
|
|
|
describe('twoMultiplicity', () => {
|
|
it('should return the multiplicity of 2 in the prime factorization of n', () => {
|
|
expect(twoMultiplicity(0n)).toEqual(0n)
|
|
expect(twoMultiplicity(1n)).toEqual(0n)
|
|
expect(twoMultiplicity(2n)).toEqual(1n)
|
|
expect(twoMultiplicity(4n)).toEqual(2n)
|
|
expect(twoMultiplicity(65536n)).toEqual(16n)
|
|
expect(twoMultiplicity(65537n)).toEqual(0n)
|
|
})
|
|
})
|
|
|
|
describe('bigIntGcd', () => {
|
|
it('should return the greatest common divisor of a and b', () => {
|
|
expect(bigIntGcd(123n, 456n)).toEqual(3n)
|
|
})
|
|
|
|
it('should correctly handle zeros', () => {
|
|
expect(bigIntGcd(0n, 0n)).toEqual(0n)
|
|
expect(bigIntGcd(0n, 1n)).toEqual(1n)
|
|
expect(bigIntGcd(1n, 0n)).toEqual(1n)
|
|
})
|
|
|
|
it('should correctly handle equal values', () => {
|
|
expect(bigIntGcd(1n, 1n)).toEqual(1n)
|
|
})
|
|
})
|
|
|
|
describe('bigIntModPow', () => {
|
|
it('should correctly calculate modular exponentiation', () => {
|
|
expect(bigIntModPow(2n, 3n, 5n)).toEqual(3n)
|
|
expect(bigIntModPow(2n, 3n, 6n)).toEqual(2n)
|
|
expect(bigIntModPow(2n, 3n, 7n)).toEqual(1n)
|
|
expect(bigIntModPow(2n, 3n, 8n)).toEqual(0n)
|
|
})
|
|
|
|
it('should correctly handle very large numbers', () => {
|
|
// calculating this with BigInt would either take forever or error with "Maximum BigInt size exceeded
|
|
expect(bigIntModPow(2n, 100000000000n, 100n)).toEqual(76n)
|
|
})
|
|
})
|
|
|
|
describe('bigIntModInv', () => {
|
|
it('should correctly calculate modular inverse', () => {
|
|
expect(bigIntModInv(2n, 5n)).toEqual(3n)
|
|
expect(bigIntModInv(2n, 7n)).toEqual(4n)
|
|
})
|
|
|
|
it("should error if there's no modular inverse", () => {
|
|
expect(() => bigIntModInv(2n, 6n)).toThrow(RangeError)
|
|
expect(() => bigIntModInv(2n, 8n)).toThrow(RangeError)
|
|
})
|
|
|
|
it('should correctly handle very large numbers', () => {
|
|
// calculating this with BigInt would either take forever or error with "Maximum BigInt size exceeded
|
|
expect(bigIntModInv(123123123123n, 1829n)).toEqual(318n)
|
|
})
|
|
})
|