-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3c99770
commit 7383a94
Showing
5 changed files
with
148 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,36 @@ | ||
import * as crypto from "node:crypto"; | ||
|
||
function rotl(x: bigint, k: bigint) { | ||
return BigInt.asUintN(64, ((x << k) | (x >> (64n - k)))); | ||
} | ||
|
||
export class RandomMapping { | ||
private state: Uint8Array; | ||
private s: BigUint64Array; | ||
lastIdx: number; | ||
|
||
constructor(seed: Uint8Array, lastIdx = 0) { | ||
this.state = crypto.createHash("sha1").update(seed).digest(); | ||
this.s = new BigUint64Array(crypto.createHash("sha256").update(seed).digest().buffer); | ||
this.lastIdx = lastIdx; | ||
} | ||
|
||
nextIndex(): number { | ||
let prng = 0n; | ||
prng |= BigInt(this.state[0]) << 0n; | ||
prng |= BigInt(this.state[1]) << 8n; | ||
prng |= BigInt(this.state[2]) << 16n; | ||
prng |= BigInt(this.state[3]) << 24n; | ||
prng |= BigInt(this.state[4]) << 32n; | ||
prng |= BigInt(this.state[5]) << 40n; | ||
prng |= BigInt(this.state[6]) << 48n; | ||
prng |= BigInt(this.state[7]) << 56n; | ||
// https://prng.di.unimi.it/xoshiro256starstar.c | ||
const result = BigInt.asUintN(64, rotl(BigInt.asUintN(64, this.s[1] * 5n), 7n) * 9n); | ||
|
||
const t = BigInt.asUintN(64, this.s[1] << 17n); | ||
|
||
this.s[2] ^= this.s[0]; | ||
this.s[3] ^= this.s[1]; | ||
this.s[1] ^= this.s[2]; | ||
this.s[0] ^= this.s[3]; | ||
|
||
this.s[2] ^= t; | ||
|
||
this.s[3] = rotl(this.s[3], 45n); | ||
|
||
this.lastIdx += Math.ceil( | ||
(this.lastIdx + 1.5) * (2 ** 32 / Math.sqrt(Number(prng) + 1) - 1), | ||
(this.lastIdx + 1.5) * (2 ** 32 / Math.sqrt(Number(result) + 1) - 1), | ||
); | ||
this.state = crypto.createHash("sha1").update(this.state).digest(); | ||
return this.lastIdx; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,111 @@ | ||
import * as crypto from 'node:crypto'; | ||
import { beforeEach, describe, expect, test } from "vitest"; | ||
import { Encoder } from "../src/riblt/encoder.js"; | ||
import { Decoder } from "../src/riblt/decoder.js"; | ||
import { SymbolFactory, type SourceSymbol } from "../src/riblt/symbol.js"; | ||
import * as crypto from 'node:crypto'; | ||
import { Encoder } from "../src/riblt/encoder.js"; | ||
import { type SourceSymbol, SymbolFactory } from "../src/riblt/symbol.js"; | ||
|
||
|
||
class VertexSymbol implements SourceSymbol { | ||
data: number; | ||
|
||
constructor(data: number) { | ||
this.data = data; | ||
} | ||
|
||
xor(s: VertexSymbol): void { | ||
this.data ^= s.data; | ||
} | ||
|
||
hash(): Uint8Array { | ||
return new Uint8Array(crypto.createHash('sha1').update(new Uint32Array([this.data])).digest()); | ||
} | ||
|
||
equals(s: VertexSymbol): boolean { | ||
return this.data === s.data; | ||
} | ||
|
||
toString(): string { | ||
return `${this.data}`; | ||
} | ||
data: number; | ||
|
||
constructor(data: number) { | ||
this.data = data; | ||
} | ||
|
||
xor(s: VertexSymbol): void { | ||
this.data ^= s.data; | ||
} | ||
|
||
hash(): Uint8Array { | ||
return new Uint8Array( | ||
crypto | ||
.createHash('sha1') | ||
.update(new Uint32Array([this.data])) | ||
.digest(), | ||
); | ||
} | ||
|
||
equals(s: VertexSymbol): boolean { | ||
return this.data === s.data; | ||
} | ||
|
||
toString(): string { | ||
return `${this.data}`; | ||
} | ||
} | ||
|
||
|
||
class VertexSymbolFactory extends SymbolFactory<VertexSymbol> { | ||
emptySource(): VertexSymbol { | ||
return new VertexSymbol(0); | ||
} | ||
emptySource(): VertexSymbol { | ||
return new VertexSymbol(0); | ||
} | ||
|
||
emptyHash(): Uint8Array { | ||
return new Uint8Array(20); | ||
} | ||
emptyHash(): Uint8Array { | ||
return new Uint8Array(20); | ||
} | ||
|
||
cloneSource(s: VertexSymbol): VertexSymbol { | ||
return new VertexSymbol(s.data); | ||
} | ||
cloneSource(s: VertexSymbol): VertexSymbol { | ||
return new VertexSymbol(s.data); | ||
} | ||
|
||
newTestSymbol(i): VertexSymbol { | ||
return new VertexSymbol(i); | ||
} | ||
newTestSymbol(i): VertexSymbol { | ||
return new VertexSymbol(i); | ||
} | ||
} | ||
|
||
|
||
describe("RIBLT test", async () => { | ||
const factory = new VertexSymbolFactory(); | ||
|
||
|
||
test.each([10, 20, 40, 100, 1000, 10000, 50000, 100000])("d=%i", async (d) => { | ||
const nlocal = d >> 1; | ||
const nremote = d >> 1; | ||
const ncommon = d; | ||
|
||
let symbolIndex = 0; | ||
|
||
const localEncoder = new Encoder(factory); | ||
const remoteEncoder = new Encoder(factory); | ||
const localDecoder = new Decoder(factory); | ||
|
||
const localSymbols: VertexSymbol[] = []; | ||
const remoteSymbols: VertexSymbol[] = []; | ||
|
||
for (let i = 0; i < nlocal; i++) { | ||
const localSymbol = factory.newTestSymbol(symbolIndex++); | ||
localSymbols.push(localSymbol); | ||
localEncoder.addSymbol(localSymbol); | ||
} | ||
for (let i = 0; i < nremote; i++) { | ||
const remoteSymbol = factory.newTestSymbol(symbolIndex++); | ||
remoteSymbols.push(remoteSymbol); | ||
remoteEncoder.addSymbol(remoteSymbol); | ||
} | ||
for (let i = 0; i < ncommon; i++) { | ||
const localSymbol = factory.newTestSymbol(symbolIndex++); | ||
const remoteSymbol = factory.cloneSource(localSymbol); | ||
localEncoder.addSymbol(localSymbol); | ||
remoteEncoder.addSymbol(remoteSymbol); | ||
} | ||
|
||
let sequenceSize = 0; | ||
do { | ||
sequenceSize++; | ||
localEncoder.producePrefix(sequenceSize); | ||
remoteEncoder.producePrefix(sequenceSize); | ||
// console.log(`localEncoder[${sequenceSize - 1}]: ${localEncoder.codedSymbols[sequenceSize - 1]}`); | ||
// console.log(`remoteEncoder[${sequenceSize - 1}]: ${remoteEncoder.codedSymbols[sequenceSize - 1]}`); | ||
localDecoder.addCodedSymbol(sequenceSize - 1, localEncoder.codedSymbols[sequenceSize - 1], remoteEncoder.codedSymbols[sequenceSize - 1]); | ||
// console.log(`localDecoder[${sequenceSize - 1}]: ${localDecoder.codedSymbols[sequenceSize - 1]}`); | ||
} while (!localDecoder.tryDecode()); | ||
|
||
// console.log(localDecoder.decodedLocalSymbols); | ||
// console.log(localDecoder.decodedRemoteSymbols); | ||
// console.log(localDecoder.remaining); | ||
|
||
console.log(sequenceSize); | ||
}); | ||
const factory = new VertexSymbolFactory(); | ||
|
||
|
||
test.each([10, 20, 40, 100, 1000, 10000, 50000, 100000, 300000])( | ||
"d=%i", | ||
async (d) => { | ||
const nlocal = d >> 1; | ||
const nremote = d >> 1; | ||
const ncommon = d; | ||
|
||
let symbolIndex = 0; | ||
|
||
const localEncoder = new Encoder(factory); | ||
const remoteEncoder = new Encoder(factory); | ||
const localDecoder = new Decoder(factory); | ||
|
||
const localSymbols: VertexSymbol[] = []; | ||
const remoteSymbols: VertexSymbol[] = []; | ||
|
||
for (let i = 0; i < nlocal; i++) { | ||
const localSymbol = factory.newTestSymbol(symbolIndex++); | ||
localSymbols.push(localSymbol); | ||
localEncoder.addSymbol(localSymbol); | ||
} | ||
for (let i = 0; i < nremote; i++) { | ||
const remoteSymbol = factory.newTestSymbol(symbolIndex++); | ||
remoteSymbols.push(remoteSymbol); | ||
remoteEncoder.addSymbol(remoteSymbol); | ||
} | ||
for (let i = 0; i < ncommon; i++) { | ||
const localSymbol = factory.newTestSymbol(symbolIndex++); | ||
const remoteSymbol = factory.cloneSource(localSymbol); | ||
localEncoder.addSymbol(localSymbol); | ||
remoteEncoder.addSymbol(remoteSymbol); | ||
} | ||
|
||
let sequenceSize = 0; | ||
do { | ||
sequenceSize++; | ||
localEncoder.producePrefix(sequenceSize); | ||
remoteEncoder.producePrefix(sequenceSize); | ||
// console.log(`localEncoder[${sequenceSize - 1}]: ${localEncoder.codedSymbols[sequenceSize - 1]}`); | ||
// console.log(`remoteEncoder[${sequenceSize - 1}]: ${remoteEncoder.codedSymbols[sequenceSize - 1]}`); | ||
localDecoder.addCodedSymbol(sequenceSize - 1, localEncoder.codedSymbols[sequenceSize - 1], remoteEncoder.codedSymbols[sequenceSize - 1]); | ||
// console.log(`localDecoder[${sequenceSize - 1}]: ${localDecoder.codedSymbols[sequenceSize - 1]}`); | ||
} while (!localDecoder.tryDecode()); | ||
|
||
// console.log(localDecoder.decodedLocalSymbols); | ||
// console.log(localDecoder.decodedRemoteSymbols); | ||
// console.log(localDecoder.remaining); | ||
|
||
console.log(`${sequenceSize/d} symbols/diff`); | ||
}); | ||
}); |