1implement Ida; 2 3# 4# M Rabin, ``Efficient Dispersal of Information for Security, 5# Load Balancing, and Fault Tolerance'', JACM 36(2), April 1989, pp. 335-348 6# the scheme used below is that suggested at the top of page 340 7# 8 9include "sys.m"; 10 sys: Sys; 11 12include "rand.m"; 13 rand: Rand; 14 15include "ida.m"; 16 17invtab: array of int; 18 19init() 20{ 21 sys = load Sys Sys->PATH; 22 rand = load Rand Rand->PATH; 23 rand->init(sys->pctl(0, nil)^(sys->millisec()<<8)); 24 # the table is in a separate module so that 25 # the copy in the module initialisation section is discarded 26 # after unloading, preventing twice the space being used 27 idatab := load Idatab Idatab->PATH; 28 invtab = idatab->init(); # the big fella 29 idatab = nil; 30} 31 32Field: con 65537; 33Fmax: con Field-1; 34 35div(a, b: int): int 36{ 37 return mul(a, invtab[b]); 38} 39 40mul(a, b: int): int 41{ 42 if(a == Fmax && b == Fmax) # avoid overflow 43 return 1; 44 return int((big(a*b) & 16rFFFFFFFF) % big Field); 45} 46 47sub(a, b: int): int 48{ 49 return ((a-b)+Field)%Field; 50} 51 52add(a, b: int): int 53{ 54 return (a + b)%Field; 55} 56 57# 58# return a fragment representing the encoded version of data 59# 60fragment(data: array of byte, m: int): ref Frag 61{ 62 nb := len data; 63 nw := (nb+1)/2; 64 a := array[m] of {* => rand->rand(Fmax)+1}; # no zero elements 65 f := array[(nw + m - 1)/m] of int; 66 o := 0; 67 i := 0; 68 for(k := 0; k < len f; k++){ 69 c := 0; 70 for(j := 0; j < m && i < nb; j++){ 71 b := int data[i++] << 8; 72 if(i < nb) 73 b |= int data[i++]; 74 c = add(c, mul(b, a[j])); 75 } 76 f[o++] = c; 77 } 78 return ref Frag(nb, m, a, f, nil); 79} 80 81# 82# return the data encoded by the given set of fragments 83# 84reconstruct(frags: array of ref Frag): (array of byte, string) 85{ 86 if(len frags < 1 || len frags < (m := frags[0].m)) 87 return (nil, "too few fragments"); 88 fraglen := len frags[0].enc; 89 90 a := array[m] of array of int; 91 for(j := 0; j < len a; j++){ 92 a[j] = frags[j].a; 93 if(len a[j] != m) 94 return (nil, "inconsistent encoding matrix"); 95 if(len frags[j].enc != fraglen) 96 return (nil, "inconsistent fragments"); 97 } 98 ainv := minvert(a); 99 out := array[fraglen*2*m] of byte; 100 o := 0; 101 for(k := 0; k < fraglen; k++){ 102 for(i := 0; i < m; i++){ 103 row := ainv[i]; 104 b := 0; 105 for(j = 0; j < m; j++) 106 b = add(b, mul(frags[j].enc[k], row[j])); 107 if((b>>16) != 0) 108 return (nil, "corrupt output"); 109 out[o++] = byte (b>>8); 110 out[o++] = byte b; 111 } 112 } 113 if(frags[0].dlen < len out) 114 out = out[0: frags[0].dlen]; 115 return (out, nil); 116} 117 118# 119# Rabin's paper gives a way of building an encoding matrix that can then 120# be inverted in O(m^2) operations, compared to O(m^3) for the following, 121# but m is small enough it doesn't seem worth the added complication, 122# and it's only done once per set 123# 124minvert(a: array of array of int): array of array of int 125{ 126 m := len a; # it's square 127 out := array[m] of {* => array[m*2] of {* => 0}}; 128 for(r := 0; r < m; r++){ 129 out[r][0:] = a[r]; 130 out[r][m+r] = 1; # identity matrix 131 } 132 for(r = 0; r < m; r++){ 133 x := out[r][r]; # by construction, cannot be zero, unless later corrupted 134 for(c := 0; c < 2*m; c++) 135 out[r][c] = div(out[r][c], x); 136 for(r1 := 0; r1 < m; r1++) 137 if(r1 != r){ 138 y := div(out[r1][r], out[r][r]); 139 for(c = 0; c < 2*m; c++) 140 out[r1][c] = sub(out[r1][c], mul(y, out[r][c])); 141 } 142 } 143 for(r = 0; r < m; r++) 144 out[r] = out[r][m:]; 145 return out; 146} 147 148Val: adt { 149 v: int; 150 n: int; 151}; 152 153addval(vl: list of ref Val, v: int): list of ref Val 154{ 155 for(l := vl; l != nil; l = tl l) 156 if((hd l).v == v){ 157 (hd l).n++; 158 return vl; 159 } 160 return ref Val(v, 1) :: vl; 161} 162 163mostly(vl: list of ref Val): ref Val 164{ 165 if(len vl == 1) 166 return hd vl; 167 v: ref Val; 168 for(; vl != nil; vl = tl vl) 169 if(v == nil || (hd vl).n > v.n) 170 v = hd vl; 171 return v; 172} 173 174# 175# return a consistent set of Frags: all parameters agree with the majority, 176# and obviously bad fragments have been discarded 177# 178# in the absence of error, they should all have the same value, so lists are fine; 179# could separately return the discarded ones, out of interest 180# 181consistent(frags: array of ref Frag): array of ref Frag 182{ 183 t := array[len frags] of ref Frag; 184 t[0:] = frags; 185 frags = t; 186 ds: list of ref Val; # data size 187 ms: list of ref Val; 188 fls: list of ref Val; 189 for(i := 0; i < len frags; i++){ 190 f := frags[i]; 191 if(f != nil){ 192 ds = addval(ds, f.dlen); 193 ms = addval(ms, f.m); 194 fls = addval(fls, len f.enc); 195 } 196 } 197 dv := mostly(ds); 198 mv := mostly(ms); 199 flv := mostly(fls); 200 if(mv == nil || flv == nil || dv == nil) 201 return nil; 202 for(i = 0; i < len frags; i++){ 203 f := frags[i]; 204 if(f == nil || f.m != mv.v || f.m != len f.a || len f.enc != flv.v || f.dlen != dv.v || badfrag(f)){ # inconsistent: drop it 205 if(i+1 < len frags) 206 frags[i:] = frags[i+1:]; 207 frags = frags[0:len frags-1]; 208 } 209 } 210 if(len frags == 0) 211 return nil; 212 return frags; 213} 214 215badfrag(f: ref Frag): int 216{ 217 for(i := 0; i < len f.a; i++){ 218 v := f.a[i]; 219 if(v <= 0 || v >= Field) 220 return 1; 221 } 222 for(i = 0; i < len f.a; i++){ 223 v := f.enc[i]; 224 if(v == 0 || v >= Field) 225 return 1; 226 } 227 return 0; 228} 229