1*4930cef6SMatthias Ringwald# 2*4930cef6SMatthias Ringwald# Copyright 2022 Google LLC 3*4930cef6SMatthias Ringwald# 4*4930cef6SMatthias Ringwald# Licensed under the Apache License, Version 2.0 (the "License"); 5*4930cef6SMatthias Ringwald# you may not use this file except in compliance with the License. 6*4930cef6SMatthias Ringwald# You may obtain a copy of the License at 7*4930cef6SMatthias Ringwald# 8*4930cef6SMatthias Ringwald# http://www.apache.org/licenses/LICENSE-2.0 9*4930cef6SMatthias Ringwald# 10*4930cef6SMatthias Ringwald# Unless required by applicable law or agreed to in writing, software 11*4930cef6SMatthias Ringwald# distributed under the License is distributed on an "AS IS" BASIS, 12*4930cef6SMatthias Ringwald# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*4930cef6SMatthias Ringwald# See the License for the specific language governing permissions and 14*4930cef6SMatthias Ringwald# limitations under the License. 15*4930cef6SMatthias Ringwald# 16*4930cef6SMatthias Ringwald 17*4930cef6SMatthias Ringwaldimport numpy as np 18*4930cef6SMatthias Ringwald 19*4930cef6SMatthias Ringwaldimport build.lc3 as lc3 20*4930cef6SMatthias Ringwaldimport tables as T, appendix_c as C 21*4930cef6SMatthias Ringwald 22*4930cef6SMatthias Ringwald 23*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 24*4930cef6SMatthias Ringwald 25*4930cef6SMatthias Ringwaldclass AttackDetector: 26*4930cef6SMatthias Ringwald 27*4930cef6SMatthias Ringwald def __init__(self, dt, sr): 28*4930cef6SMatthias Ringwald 29*4930cef6SMatthias Ringwald self.dt = dt 30*4930cef6SMatthias Ringwald self.sr = sr 31*4930cef6SMatthias Ringwald self.ms = T.DT_MS[dt] 32*4930cef6SMatthias Ringwald 33*4930cef6SMatthias Ringwald self.xn1 = 0 34*4930cef6SMatthias Ringwald self.xn2 = 0 35*4930cef6SMatthias Ringwald self.en1 = 0 36*4930cef6SMatthias Ringwald self.an1 = 0 37*4930cef6SMatthias Ringwald self.p_att = 0 38*4930cef6SMatthias Ringwald 39*4930cef6SMatthias Ringwald def is_enabled(self, nbytes): 40*4930cef6SMatthias Ringwald 41*4930cef6SMatthias Ringwald c1 = self.dt == T.DT_10M and \ 42*4930cef6SMatthias Ringwald self.sr == T.SRATE_32K and nbytes > 80 43*4930cef6SMatthias Ringwald 44*4930cef6SMatthias Ringwald c2 = self.dt == T.DT_10M and \ 45*4930cef6SMatthias Ringwald self.sr >= T.SRATE_48K and nbytes >= 100 46*4930cef6SMatthias Ringwald 47*4930cef6SMatthias Ringwald c3 = self.dt == T.DT_7M5 and \ 48*4930cef6SMatthias Ringwald self.sr == T.SRATE_32K and nbytes >= 61 and nbytes < 150 49*4930cef6SMatthias Ringwald 50*4930cef6SMatthias Ringwald c4 = self.dt == T.DT_7M5 and \ 51*4930cef6SMatthias Ringwald self.sr >= T.SRATE_48K and nbytes >= 75 and nbytes < 150 52*4930cef6SMatthias Ringwald 53*4930cef6SMatthias Ringwald return c1 or c2 or c3 or c4 54*4930cef6SMatthias Ringwald 55*4930cef6SMatthias Ringwald def run(self, nbytes, x): 56*4930cef6SMatthias Ringwald 57*4930cef6SMatthias Ringwald ### 3.3.6.2 Downsampling and filtering input 58*4930cef6SMatthias Ringwald 59*4930cef6SMatthias Ringwald mf = int(16 * self.ms) 60*4930cef6SMatthias Ringwald 61*4930cef6SMatthias Ringwald r = len(x) // mf 62*4930cef6SMatthias Ringwald x_att = np.array([ np.sum(x[i*r:(i+1)*r]) for i in range(mf) ]) 63*4930cef6SMatthias Ringwald 64*4930cef6SMatthias Ringwald x_hp = np.empty(mf) 65*4930cef6SMatthias Ringwald x_hp[0 ] = 0.375 * x_att[0 ] - 0.5 * self.xn1 + 0.125 * self.xn2 66*4930cef6SMatthias Ringwald x_hp[1 ] = 0.375 * x_att[1 ] - 0.5 * x_att[0 ] + 0.125 * self.xn1 67*4930cef6SMatthias Ringwald x_hp[2:] = 0.375 * x_att[2:] - 0.5 * x_att[1:-1] + 0.125 * x_att[0:-2] 68*4930cef6SMatthias Ringwald self.xn2 = x_att[-2] 69*4930cef6SMatthias Ringwald self.xn1 = x_att[-1] 70*4930cef6SMatthias Ringwald 71*4930cef6SMatthias Ringwald ### 3.3.6.3 Energy calculation 72*4930cef6SMatthias Ringwald 73*4930cef6SMatthias Ringwald nb = int(self.ms / 2.5) 74*4930cef6SMatthias Ringwald 75*4930cef6SMatthias Ringwald e_att = np.array([ np.sum(np.square(x_hp[40*i:40*(i+1)])) 76*4930cef6SMatthias Ringwald for i in range(nb) ]) 77*4930cef6SMatthias Ringwald 78*4930cef6SMatthias Ringwald a_att = np.empty(nb) 79*4930cef6SMatthias Ringwald a_att[0] = np.maximum(0.25 * self.an1, self.en1) 80*4930cef6SMatthias Ringwald for i in range(1,nb): 81*4930cef6SMatthias Ringwald a_att[i] = np.maximum(0.25 * a_att[i-1], e_att[i-1]) 82*4930cef6SMatthias Ringwald self.en1 = e_att[-1] 83*4930cef6SMatthias Ringwald self.an1 = a_att[-1] 84*4930cef6SMatthias Ringwald 85*4930cef6SMatthias Ringwald ### 3.3.6.4 Attack Detection 86*4930cef6SMatthias Ringwald 87*4930cef6SMatthias Ringwald p_att = -1 88*4930cef6SMatthias Ringwald flags = [ (e_att[i] > 8.5 * a_att[i]) for i in range(nb) ] 89*4930cef6SMatthias Ringwald 90*4930cef6SMatthias Ringwald for (i, f) in enumerate(flags): 91*4930cef6SMatthias Ringwald if f: p_att = i 92*4930cef6SMatthias Ringwald 93*4930cef6SMatthias Ringwald f_att = p_att >= 0 or self.p_att - 1 >= nb // 2 94*4930cef6SMatthias Ringwald self.p_att = 1 + p_att 95*4930cef6SMatthias Ringwald 96*4930cef6SMatthias Ringwald return self.is_enabled(nbytes) and f_att 97*4930cef6SMatthias Ringwald 98*4930cef6SMatthias Ringwald 99*4930cef6SMatthias Ringwalddef initial_state(): 100*4930cef6SMatthias Ringwald return { 'en1': 0.0, 'an1': 0.0, 'p_att': 0 } 101*4930cef6SMatthias Ringwald 102*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 103*4930cef6SMatthias Ringwald 104*4930cef6SMatthias Ringwalddef check_enabling(rng, dt): 105*4930cef6SMatthias Ringwald 106*4930cef6SMatthias Ringwald ok = True 107*4930cef6SMatthias Ringwald 108*4930cef6SMatthias Ringwald for sr in range(T.SRATE_16K, T.NUM_SRATE): 109*4930cef6SMatthias Ringwald 110*4930cef6SMatthias Ringwald attdet = AttackDetector(dt, sr) 111*4930cef6SMatthias Ringwald 112*4930cef6SMatthias Ringwald for nbytes in [ 61, 61-1, 75-1, 75, 80, 80+1, 100-1, 100, 150-1, 150 ]: 113*4930cef6SMatthias Ringwald 114*4930cef6SMatthias Ringwald f_att = lc3.attdet_run(dt, sr, nbytes, 115*4930cef6SMatthias Ringwald initial_state(), 2 * rng.random(T.NS[dt][sr]+6) - 1) 116*4930cef6SMatthias Ringwald 117*4930cef6SMatthias Ringwald ok = ok and f_att == attdet.is_enabled(nbytes) 118*4930cef6SMatthias Ringwald 119*4930cef6SMatthias Ringwald return ok 120*4930cef6SMatthias Ringwald 121*4930cef6SMatthias Ringwalddef check_unit(rng, dt, sr): 122*4930cef6SMatthias Ringwald 123*4930cef6SMatthias Ringwald ns = T.NS[dt][sr] 124*4930cef6SMatthias Ringwald ok = True 125*4930cef6SMatthias Ringwald 126*4930cef6SMatthias Ringwald attdet = AttackDetector(dt, sr) 127*4930cef6SMatthias Ringwald 128*4930cef6SMatthias Ringwald state_c = initial_state() 129*4930cef6SMatthias Ringwald x_c = np.zeros(ns+6) 130*4930cef6SMatthias Ringwald 131*4930cef6SMatthias Ringwald for run in range(100): 132*4930cef6SMatthias Ringwald 133*4930cef6SMatthias Ringwald ### Generate noise, and an attack at random point 134*4930cef6SMatthias Ringwald 135*4930cef6SMatthias Ringwald x = ((2 * rng.random(ns)) - 1) * (2 ** 8 - 1) 136*4930cef6SMatthias Ringwald x[(ns * rng.random()).astype(int)] *= 2 ** 7 137*4930cef6SMatthias Ringwald 138*4930cef6SMatthias Ringwald ### Check Implementation 139*4930cef6SMatthias Ringwald 140*4930cef6SMatthias Ringwald f_att = attdet.run(100, x) 141*4930cef6SMatthias Ringwald 142*4930cef6SMatthias Ringwald x_c = np.append(x_c[-6:], x) 143*4930cef6SMatthias Ringwald f_att_c = lc3.attdet_run(dt, sr, 100, state_c, x_c) 144*4930cef6SMatthias Ringwald 145*4930cef6SMatthias Ringwald ok = ok and f_att_c == f_att 146*4930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(1 - state_c['en1']/attdet.en1)) < 2 147*4930cef6SMatthias Ringwald ok = ok and np.amax(np.abs(1 - state_c['an1']/attdet.an1)) < 2 148*4930cef6SMatthias Ringwald ok = ok and state_c['p_att'] == attdet.p_att 149*4930cef6SMatthias Ringwald 150*4930cef6SMatthias Ringwald return ok 151*4930cef6SMatthias Ringwald 152*4930cef6SMatthias Ringwalddef check_appendix_c(dt): 153*4930cef6SMatthias Ringwald 154*4930cef6SMatthias Ringwald sr = T.SRATE_48K 155*4930cef6SMatthias Ringwald 156*4930cef6SMatthias Ringwald state = initial_state() 157*4930cef6SMatthias Ringwald 158*4930cef6SMatthias Ringwald x = np.append(np.zeros(6), C.X_PCM_ATT[dt][0]) 159*4930cef6SMatthias Ringwald f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x) 160*4930cef6SMatthias Ringwald ok = f_att == C.F_ATT[dt][0] 161*4930cef6SMatthias Ringwald 162*4930cef6SMatthias Ringwald x = np.append(x[-6:], C.X_PCM_ATT[dt][1]) 163*4930cef6SMatthias Ringwald f_att = lc3.attdet_run(dt, sr, C.NBYTES_ATT[dt], state, x) 164*4930cef6SMatthias Ringwald ok = f_att == C.F_ATT[dt][1] 165*4930cef6SMatthias Ringwald 166*4930cef6SMatthias Ringwald return ok 167*4930cef6SMatthias Ringwald 168*4930cef6SMatthias Ringwalddef check(): 169*4930cef6SMatthias Ringwald 170*4930cef6SMatthias Ringwald rng = np.random.default_rng(1234) 171*4930cef6SMatthias Ringwald ok = True 172*4930cef6SMatthias Ringwald 173*4930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 174*4930cef6SMatthias Ringwald ok and check_enabling(rng, dt) 175*4930cef6SMatthias Ringwald 176*4930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 177*4930cef6SMatthias Ringwald for sr in range(T.SRATE_32K, T.NUM_SRATE): 178*4930cef6SMatthias Ringwald ok = ok and check_unit(rng, dt, sr) 179*4930cef6SMatthias Ringwald 180*4930cef6SMatthias Ringwald for dt in range(T.NUM_DT): 181*4930cef6SMatthias Ringwald ok = ok and check_appendix_c(dt) 182*4930cef6SMatthias Ringwald 183*4930cef6SMatthias Ringwald return ok 184*4930cef6SMatthias Ringwald 185*4930cef6SMatthias Ringwald### ------------------------------------------------------------------------ ### 186