-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcauchy_erasure_code.js
118 lines (103 loc) · 2.97 KB
/
cauchy_erasure_code.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// @flow
'use strict';
/* ::
import { Matrix, newCauchyMatrix } from './matrix';
import { Field256Element } from './field_256';
*/
/* global Matrix, newCauchyMatrix, Field256Element */
// eslint-disable-next-line no-unused-vars
const computeParityMatrix = (
n /* : number */,
m /* : number */
) /* : Matrix<Field256Element> */ => {
const x = [];
for (let i = 0; i < m; i += 1) {
x.push(new Field256Element(n + i));
}
const y = [];
for (let i = 0; i < n; i += 1) {
y.push(new Field256Element(i));
}
return newCauchyMatrix(x, y);
};
// eslint-disable-next-line no-unused-vars
const computeParity = (
d /* : Field256Element[] */,
m /* : number */
) /* : Field256Element[] */ => {
const n = d.length;
const P = computeParityMatrix(n, m);
const dCol = new Matrix(n, 1, d);
const pCol = P.times(dCol);
return pCol.elements();
};
class NotEnoughKnownBytesError extends Error {
// flowlint-next-line unclear-type:off
constructor(...params /* : any[] */) {
super('Not enough known bytes to reconstruct', ...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, NotEnoughKnownBytesError);
}
}
}
// eslint-disable-next-line no-unused-vars
const computeReconstructionIntermediates = (
partialD /* : (?Field256Element)[] */,
partialP /* : (?Field256Element)[] */
) /* : { bytesToUse: Field256Element[], M: Matrix<Field256Element> } */ => {
const n = partialD.length;
const m = partialP.length;
const knownData = [];
const knownDataIndices = [];
for (let i = 0; i < n; i += 1) {
if (partialD[i] instanceof Field256Element) {
knownData.push(partialD[i]);
knownDataIndices.push(i);
}
}
const parityToUse = [];
const parityIndicesToUse = [];
for (let i = 0; i < m && knownData.length + parityToUse.length < n; i += 1) {
if (partialP[i] instanceof Field256Element) {
parityToUse.push(partialP[i]);
parityIndicesToUse.push(i);
}
}
if (knownData.length + parityToUse.length < n) {
throw new NotEnoughKnownBytesError();
}
const P = computeParityMatrix(n, m);
const M = new Matrix(n, n, (i, j) => {
if (i < knownDataIndices.length) {
return knownDataIndices[i] === j
? Field256Element.One
: Field256Element.Zero;
}
return P.at(parityIndicesToUse[i - knownDataIndices.length], j);
});
return { bytesToUse: knownData.concat(parityToUse), M };
};
// eslint-disable-next-line no-unused-vars
const reconstructData = (
partialD /* : (?Field256Element)[] */,
partialP /* : (?Field256Element)[] */
) /* : Field256Element[] */ => {
const n = partialD.length;
const { bytesToUse, M } = computeReconstructionIntermediates(
partialD,
partialP
);
const MInv = M.inverse();
const bytesToUseCol = new Matrix(n, 1, bytesToUse);
const dCol = MInv.times(bytesToUseCol);
return dCol.elements();
};
/* ::
export {
computeParityMatrix,
computeParity,
computeReconstructionIntermediates,
reconstructData,
NotEnoughKnownBytesError,
};
*/