@bcts/spqr 1.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +11 -0
- package/dist/index.cjs +4321 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +115 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +115 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +4318 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +4312 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +74 -0
- package/src/authenticator.ts +163 -0
- package/src/chain.ts +522 -0
- package/src/constants.ts +90 -0
- package/src/encoding/gf.ts +190 -0
- package/src/encoding/index.ts +15 -0
- package/src/encoding/polynomial.ts +657 -0
- package/src/error.ts +75 -0
- package/src/incremental-mlkem768.ts +546 -0
- package/src/index.ts +415 -0
- package/src/kdf.ts +34 -0
- package/src/proto/index.ts +1376 -0
- package/src/proto/pq-ratchet-types.ts +195 -0
- package/src/types.ts +81 -0
- package/src/util.ts +61 -0
- package/src/v1/chunked/index.ts +60 -0
- package/src/v1/chunked/message.ts +257 -0
- package/src/v1/chunked/send-ct.ts +352 -0
- package/src/v1/chunked/send-ek.ts +285 -0
- package/src/v1/chunked/serialize.ts +278 -0
- package/src/v1/chunked/states.ts +399 -0
- package/src/v1/index.ts +9 -0
- package/src/v1/unchunked/index.ts +20 -0
- package/src/v1/unchunked/send-ct.ts +231 -0
- package/src/v1/unchunked/send-ek.ts +177 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2025 Signal Messenger, LLC
|
|
3
|
+
* Copyright © 2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
* GF(2^16) Galois field arithmetic.
|
|
6
|
+
* Ported from the Rust SPQR implementation.
|
|
7
|
+
*
|
|
8
|
+
* Primitive polynomial: x^16 + x^12 + x^3 + x + 1 (0x1100b)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Constants
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
/** Primitive polynomial for GF(2^16): x^16 + x^12 + x^3 + x + 1 */
|
|
16
|
+
export const POLY = 0x1_100b;
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Precomputed reduction table (256 entries)
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build one entry of the reduction table.
|
|
24
|
+
*
|
|
25
|
+
* Given a single byte `a` that appears in positions [16..23] or [24..31] of
|
|
26
|
+
* a 32-bit product, compute the 16-bit XOR mask needed to reduce those bits
|
|
27
|
+
* modulo POLY.
|
|
28
|
+
*/
|
|
29
|
+
function reduceFromByte(a: number): number {
|
|
30
|
+
let byte = a;
|
|
31
|
+
let out = 0;
|
|
32
|
+
for (let i = 7; i >= 0; i--) {
|
|
33
|
+
if (((1 << i) & byte) !== 0) {
|
|
34
|
+
out ^= POLY << i;
|
|
35
|
+
byte ^= ((POLY << i) >>> 16) & 0xff;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out & 0xffff;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Precomputed 256-entry lookup table for polynomial reduction. */
|
|
42
|
+
const REDUCE_BYTES: Uint16Array = /* @__PURE__ */ (() => {
|
|
43
|
+
const table = new Uint16Array(256);
|
|
44
|
+
for (let i = 0; i < 256; i++) {
|
|
45
|
+
table[i] = reduceFromByte(i);
|
|
46
|
+
}
|
|
47
|
+
return table;
|
|
48
|
+
})();
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Low-level polynomial arithmetic (operates on raw u16/u32 numbers)
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Polynomial multiplication in GF(2)[x] (no reduction).
|
|
56
|
+
*
|
|
57
|
+
* Both `a` and `b` must be in the range [0, 0xffff].
|
|
58
|
+
* The result may be up to 31 bits wide.
|
|
59
|
+
*/
|
|
60
|
+
function polyMul(a: number, b: number): number {
|
|
61
|
+
let acc = 0;
|
|
62
|
+
for (let shift = 0; shift < 16; shift++) {
|
|
63
|
+
if ((b & (1 << shift)) !== 0) {
|
|
64
|
+
acc ^= a << shift;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Keep as unsigned 32-bit
|
|
68
|
+
return acc >>> 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Reduce a 32-bit polynomial product modulo POLY, yielding a 16-bit result.
|
|
73
|
+
*
|
|
74
|
+
* Uses the precomputed REDUCE_BYTES table to process the top two bytes.
|
|
75
|
+
*/
|
|
76
|
+
export function polyReduce(v: number): number {
|
|
77
|
+
let r = v >>> 0;
|
|
78
|
+
// Reduce byte at positions [24..31]
|
|
79
|
+
r ^= REDUCE_BYTES[(r >>> 24) & 0xff] << 8;
|
|
80
|
+
// Reduce byte at positions [16..23]
|
|
81
|
+
r ^= REDUCE_BYTES[(r >>> 16) & 0xff];
|
|
82
|
+
return r & 0xffff;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Full GF(2^16) multiplication of two raw u16 values.
|
|
87
|
+
* Returns a u16 result.
|
|
88
|
+
*/
|
|
89
|
+
function mulRaw(a: number, b: number): number {
|
|
90
|
+
return polyReduce(polyMul(a, b));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// GF16 class
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* An element of GF(2^16).
|
|
99
|
+
*
|
|
100
|
+
* The `value` field holds a 16-bit unsigned integer in [0, 65535].
|
|
101
|
+
*/
|
|
102
|
+
export class GF16 {
|
|
103
|
+
readonly value: number;
|
|
104
|
+
|
|
105
|
+
constructor(value: number) {
|
|
106
|
+
this.value = value & 0xffff;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// -- Static constants -----------------------------------------------------
|
|
110
|
+
|
|
111
|
+
static readonly ZERO = new GF16(0);
|
|
112
|
+
static readonly ONE = new GF16(1);
|
|
113
|
+
|
|
114
|
+
// -- Arithmetic -----------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
/** Addition in GF(2^n) is XOR. */
|
|
117
|
+
add(other: GF16): GF16 {
|
|
118
|
+
return new GF16(this.value ^ other.value);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Subtraction in GF(2^n) is the same as addition (XOR). */
|
|
122
|
+
sub(other: GF16): GF16 {
|
|
123
|
+
return this.add(other);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Multiplication in GF(2^16) using polynomial long-multiplication + reduction. */
|
|
127
|
+
mul(other: GF16): GF16 {
|
|
128
|
+
return new GF16(mulRaw(this.value, other.value));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Division in GF(2^16).
|
|
133
|
+
*
|
|
134
|
+
* Computes `this / other` via Fermat's little theorem:
|
|
135
|
+
* other^(-1) = other^(2^16 - 2)
|
|
136
|
+
*
|
|
137
|
+
* The loop accumulates the inverse through repeated squaring:
|
|
138
|
+
* After 15 iterations (i = 1..15):
|
|
139
|
+
* out = this * other^(2^16 - 2) = this * other^(-1)
|
|
140
|
+
*
|
|
141
|
+
* Throws if `other` is zero.
|
|
142
|
+
*/
|
|
143
|
+
div(other: GF16): GF16 {
|
|
144
|
+
if (other.value === 0) {
|
|
145
|
+
throw new Error("GF16: division by zero");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let sqVal = mulRaw(other.value, other.value); // other^2
|
|
149
|
+
let outVal = this.value;
|
|
150
|
+
|
|
151
|
+
for (let i = 1; i < 16; i++) {
|
|
152
|
+
// Compute both products using the OLD square value
|
|
153
|
+
const newSqVal = mulRaw(sqVal, sqVal);
|
|
154
|
+
const newOutVal = mulRaw(sqVal, outVal);
|
|
155
|
+
sqVal = newSqVal;
|
|
156
|
+
outVal = newOutVal;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return new GF16(outVal);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// -- Comparison -----------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
equals(other: GF16): boolean {
|
|
165
|
+
return this.value === other.value;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// -- Display --------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
toString(): string {
|
|
171
|
+
return `GF16(0x${this.value.toString(16).padStart(4, "0")})`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Parallel multiplication
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Multiply every element of `into` by `a` in-place.
|
|
181
|
+
*
|
|
182
|
+
* This is the TypeScript equivalent of Rust's `parallel_mult` which benefits
|
|
183
|
+
* from SIMD on native platforms. Here we just iterate.
|
|
184
|
+
*/
|
|
185
|
+
export function parallelMult(a: GF16, into: GF16[]): void {
|
|
186
|
+
const av = a.value;
|
|
187
|
+
for (let i = 0; i < into.length; i++) {
|
|
188
|
+
into[i] = new GF16(mulRaw(av, into[i].value));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © 2025 Signal Messenger, LLC
|
|
3
|
+
* Copyright © 2026 Parity Technologies
|
|
4
|
+
*
|
|
5
|
+
* Erasure coding module: GF(2^16) field arithmetic and polynomial encoding.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// GF(2^16) field arithmetic
|
|
9
|
+
export { GF16, POLY, polyReduce, parallelMult } from "./gf.js";
|
|
10
|
+
|
|
11
|
+
// Polynomial erasure coding
|
|
12
|
+
export { Poly, PolyEncoder, PolyDecoder, PolynomialError } from "./polynomial.js";
|
|
13
|
+
|
|
14
|
+
// Types
|
|
15
|
+
export type { Chunk, Encoder, Decoder, Pt } from "./polynomial.js";
|