14930cef6SMatthias Ringwald# 24930cef6SMatthias Ringwald# Copyright 2022 Google LLC 34930cef6SMatthias Ringwald# 44930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License"); 54930cef6SMatthias Ringwald# you may not use this file except in compliance with the License. 64930cef6SMatthias Ringwald# You may obtain a copy of the License at 74930cef6SMatthias Ringwald# 84930cef6SMatthias Ringwald# http://www.apache.org/licenses/LICENSE-2.0 94930cef6SMatthias Ringwald# 104930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software 114930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS, 124930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134930cef6SMatthias Ringwald# See the License for the specific language governing permissions and 144930cef6SMatthias Ringwald# limitations under the License. 154930cef6SMatthias Ringwald# 164930cef6SMatthias Ringwald 174930cef6SMatthias Ringwaldimport numpy as np 184930cef6SMatthias Ringwald 194c4eb519SMatthias Ringwaldimport lc3 204930cef6SMatthias Ringwaldimport tables as T, appendix_c as C 214930cef6SMatthias Ringwald 224930cef6SMatthias Ringwald 234930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 244930cef6SMatthias Ringwald 254930cef6SMatthias Ringwaldclass AttackDetector: 264930cef6SMatthias Ringwald 274930cef6SMatthias Ringwald def __init__(self, dt, sr): 284930cef6SMatthias Ringwald 294930cef6SMatthias Ringwald self.dt = dt 304930cef6SMatthias Ringwald self.sr = sr 314930cef6SMatthias Ringwald self.ms = T.DT_MS[dt] 324930cef6SMatthias Ringwald 334930cef6SMatthias Ringwald self.xn1 = 0 344930cef6SMatthias Ringwald self.xn2 = 0 354930cef6SMatthias Ringwald self.en1 = 0 364930cef6SMatthias Ringwald self.an1 = 0 374930cef6SMatthias Ringwald self.p_att = 0 384930cef6SMatthias Ringwald 394930cef6SMatthias Ringwald def is_enabled(self, nbytes): 404930cef6SMatthias Ringwald 414930cef6SMatthias Ringwald c1 = self.dt == T.DT_10M and \ 424930cef6SMatthias Ringwald self.sr == T.SRATE_32K and nbytes > 80 434930cef6SMatthias Ringwald 444930cef6SMatthias Ringwald c2 = self.dt == T.DT_10M and \ 454930cef6SMatthias Ringwald self.sr >= T.SRATE_48K and nbytes >= 100 464930cef6SMatthias Ringwald 474930cef6SMatthias Ringwald c3 = self.dt == T.DT_7M5 and \ 484930cef6SMatthias Ringwald self.sr == T.SRATE_32K and nbytes >= 61 and nbytes < 150 494930cef6SMatthias Ringwald 504930cef6SMatthias Ringwald c4 = self.dt == T.DT_7M5 and \ 514930cef6SMatthias Ringwald self.sr >= T.SRATE_48K and nbytes >= 75 and nbytes < 150 524930cef6SMatthias Ringwald 534930cef6SMatthias Ringwald return c1 or c2 or c3 or c4 544930cef6SMatthias Ringwald 554930cef6SMatthias Ringwald def run(self, nbytes, x): 564930cef6SMatthias Ringwald 57*6897da5cSDirk Helbig ### Downsampling and filtering input 584930cef6SMatthias Ringwald 594930cef6SMatthias Ringwald mf = int(16 * self.ms) 604930cef6SMatthias Ringwald 614930cef6SMatthias Ringwald r = len(x) // mf 624930cef6SMatthias Ringwald x_att = np.array([ np.sum(x[i*r:(i+1)*r]) for i in range(mf) ]) 634930cef6SMatthias Ringwald 644930cef6SMatthias Ringwald x_hp = np.empty(mf) 654930cef6SMatthias Ringwald x_hp[0 ] = 0.375 * x_att[0 ] - 0.5 * self.xn1 + 0.125 * self.xn2 664930cef6SMatthias Ringwald x_hp[1 ] = 0.375 * x_att[1 ] - 0.5 * x_att[0 ] + 0.125 * self.xn1 674930cef6SMatthias Ringwald x_hp[2:] = 0.375 * x_att[2:] - 0.5 * x_att[1:-1] + 0.125 * x_att[0:-2] 684930cef6SMatthias Ringwald self.xn2 = x_att[-2] 694930cef6SMatthias Ringwald self.xn1 = x_att[-1] 704930cef6SMatthias Ringwald 71*6897da5cSDirk Helbig ### Energy calculation 724930cef6SMatthias Ringwald 734930cef6SMatthias Ringwald nb = int(self.ms / 2.5) 744930cef6SMatthias Ringwald 754930cef6SMatthias Ringwald e_att = np.array([ np.sum(np.square(x_hp[40*i:40*(i+1)])) 764930cef6SMatthias Ringwald for i in range(nb) ]) 774930cef6SMatthias Ringwald 784930cef6SMatthias Ringwald a_att = np.empty(nb) 794930cef6SMatthias Ringwald a_att[0] = np.maximum(0.25 * self.an1, self.en1) 804930cef6SMatthias Ringwald for i in range(1,nb): 814930cef6SMatthias Ringwald a_att[i] = np.maximum(0.25 * a_att[i-1], e_att[i-1]) 824930cef6SMatthias Ringwald self.en1 = e_att[-1] 834930cef6SMatthias Ringwald self.an1 = a_att[-1] 844930cef6SMatthias Ringwald 85*6897da5cSDirk Helbig ### Attack Detection 864930cef6SMatthias Ringwald 874930cef6SMatthias Ringwald p_att = -1 884930cef6SMatthias Ringwald flags = [ (e_att[i] > 8.5 * a_att[i]) for i in range(nb) ] 894930cef6SMatthias Ringwald 904930cef6SMatthias Ringwald for (i, f) in enumerate(flags): 914930cef6SMatthias Ringwald if f: p_att = i 924930cef6SMatthias Ringwald 934930cef6SMatthias Ringwald f_att = p_att >= 0 or self.p_att - 1 >= nb // 2 944930cef6SMatthias Ringwald self.p_att = 1 + p_att 954930cef6SMatthias Ringwald 964930cef6SMatthias Ringwald return self.is_enabled(nbytes) and f_att 974930cef6SMatthias Ringwald 984930cef6SMatthias Ringwald 994930cef6SMatthias Ringwalddef initial_state(): 1004930cef6SMatthias Ringwald return { 'en1': 0.0, 'an1': 0.0, 'p_att': 0 } 1014930cef6SMatthias Ringwald 1024930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 1034930cef6SMatthias Ringwald 1044930cef6SMatthias Ringwalddef check_enabling(rng, dt): 1054930cef6SMatthias Ringwald 1064930cef6SMatthias Ringwald ok = True 1074930cef6SMatthias Ringwald 108*6897da5cSDirk Helbig for sr in range(T.SRATE_8K, T.SRATE_48K + 1): 1094930cef6SMatthias Ringwald 1104930cef6SMatthias Ringwald attdet = AttackDetector(dt, sr) 1114930cef6SMatthias Ringwald 1124930cef6SMatthias Ringwald for nbytes in [ 61, 61-1, 75-1, 75, 80, 80+1, 100-1, 100, 150-1, 150 ]: 1134930cef6SMatthias Ringwald 1144930cef6SMatthias Ringwald f_att = lc3.attdet_run(dt, sr, nbytes, 1154930cef6SMatthias Ringwald initial_state(), 2 * rng.random(T.NS[dt][sr]+6) - 1) 1164930cef6SMatthias Ringwald 1174930cef6SMatthias Ringwald ok = ok and f_att == attdet.is_enabled(nbytes) 1184930cef6SMatthias Ringwald 1194930cef6SMatthias Ringwald return ok 1204930cef6SMatthias Ringwald 1214930cef6SMatthias Ringwalddef check_unit(rng, dt, sr): 1224930cef6SMatthias Ringwald 1234930cef6SMatthias Ringwald ns = T.NS[dt][sr] 1244930cef6SMatthias Ringwald ok = True 1254930cef6SMatthias Ringwald 1264930cef6SMatthias Ringwald attdet = AttackDetector(dt, sr) 1274930cef6SMatthias Ringwald 1284930cef6SMatthias Ringwald state_c = initial_state() 1294930cef6SMatthias Ringwald x_c = np.zeros(ns+6) 1304930cef6SMatthias Ringwald 1314930cef6SMatthias Ringwald for run in range(100): 1324930cef6SMatthias Ringwald 1334930cef6SMatthias Ringwald ### Generate noise, and an attack at random point 1344930cef6SMatthias Ringwald 1354930cef6SMatthias Ringwald x = ((2 * rng.random(ns)) - 1) * (2 ** 8 - 1) 1364930cef6SMatthias Ringwald x[(ns * rng.random()).astype(int)] *= 2 ** 7 1374930cef6SMatthias Ringwald 1384930cef6SMatthias Ringwald ### Check Implementation 1394930cef6SMatthias Ringwald 1404930cef6SMatthias Ringwald f_att = attdet.run(100, x) 1414930cef6SMatthias Ringwald 1424930cef6SMatthias Ringwald x_c = np.append(x_c[-6:], x) 1434930cef6SMatthias Ringwald f_att_c = lc3.attdet_run(dt, sr, 100, state_c, x_c) 1444930cef6SMatthias Ringwald 1454930cef6SMatthias Ringwald ok = ok and f_att_c == f_att 1464930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(1 - state_c['en1']/attdet.en1)) < 2 1474930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(1 - state_c['an1']/attdet.an1)) < 2 1484930cef6SMatthias Ringwald ok = ok and state_c['p_att'] == attdet.p_att 1494930cef6SMatthias Ringwald 1504930cef6SMatthias Ringwald return ok 1514930cef6SMatthias Ringwald 1524930cef6SMatthias Ringwalddef check_appendix_c(dt): 1534930cef6SMatthias Ringwald 154*6897da5cSDirk Helbig i0 = dt - T.DT_7M5 1554930cef6SMatthias Ringwald sr = T.SRATE_48K 1564930cef6SMatthias Ringwald 157*6897da5cSDirk Helbig ok = True 1584930cef6SMatthias Ringwald state = initial_state() 1594930cef6SMatthias Ringwald 160*6897da5cSDirk Helbig x = np.append(np.zeros(6), C.X_PCM_ATT[i0][0]) 161*6897da5cSDirk Helbig f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[i0], state, x) 162*6897da5cSDirk Helbig ok = ok and f_att == C.F_ATT[i0][0] 1634930cef6SMatthias Ringwald 164*6897da5cSDirk Helbig x = np.append(x[-6:], C.X_PCM_ATT[i0][1]) 165*6897da5cSDirk Helbig f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[i0], state, x) 166*6897da5cSDirk Helbig ok = ok and f_att == C.F_ATT[i0][1] 1674930cef6SMatthias Ringwald 1684930cef6SMatthias Ringwald return ok 1694930cef6SMatthias Ringwald 1704930cef6SMatthias Ringwalddef check(): 1714930cef6SMatthias Ringwald 1724930cef6SMatthias Ringwald rng = np.random.default_rng(1234) 1734930cef6SMatthias Ringwald ok = True 1744930cef6SMatthias Ringwald 1754930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 1764930cef6SMatthias Ringwald ok and check_enabling(rng, dt) 1774930cef6SMatthias Ringwald 178*6897da5cSDirk Helbig for dt in ( T.DT_7M5, T.DT_10M ): 179*6897da5cSDirk Helbig for sr in ( T.SRATE_32K, T.SRATE_48K ): 1804930cef6SMatthias Ringwald ok = ok and check_unit(rng, dt, sr) 1814930cef6SMatthias Ringwald 182*6897da5cSDirk Helbig for dt in ( T.DT_7M5, T.DT_10M ): 1834930cef6SMatthias Ringwald ok = ok and check_appendix_c(dt) 1844930cef6SMatthias Ringwald 1854930cef6SMatthias Ringwald return ok 1864930cef6SMatthias Ringwald 1874930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 188