def step_t_5(a_base, B, p1): if p1 <= int(root(B, 5)): ### Посчет времени работы start_time = time.time() ### n_list = [] l = 5 if p1 % 4 == 3: n_list = [p1] q_3k4 = readfile("primes/4k+3.txt") sign_p1 = [] for a in a_base: sign_p1.append(numth.jacobi(a, p1)) for q in q_3k4: if q % 24 == p1 % 24: sign_q = [] for a in a_base: sign_q.append(numth.jacobi(a, q)) if sign_q == sign_p1: n_list.append(q) # else: # for p in primes: ### total_time = "--- %s seconds ---\n" % (time.time() - start_time) ### return np.array(n_list) else: print(f"Value Error: p1 > {int(root(B, 5))}")
def verify(pubkey, signature, message_hash): '''Verify a Schnorr signature, returning True if valid. May raise a ValueError or return False on failure. `pubkey` should be the the raw public key bytes (as you would get from bitcoin.pubic_key_from_private_key, after hex decoding, etc). `signature` should be the 64 byte schnorr signature as would be returned from `sign` above. `message_hash` should be the 32 byte sha256d hash of the tx message to be verified''' if not isinstance(pubkey, bytes) or len(pubkey) not in (33, 65): raise ValueError('pubkey must be a bytes object of either length 33 or 65') if not isinstance(signature, bytes) or len(signature) != 64: raise ValueError('signature must be a bytes object of length 64') if not isinstance(message_hash, bytes) or len(message_hash) != 32: raise ValueError('message_hash must be a bytes object of length 32') G = ecdsa.SECP256k1.generator order = G.order() fieldsize = G.curve().p() try: pubpoint = ser_to_point(pubkey) except: # off-curve points, failed decompression, bad format, # point at infinity: raise ValueError('pubkey could not be parsed') rbytes = signature[:32] ## these unnecessary since below we do bytes comparison and ## R.x() is always < fieldsize. # r = int.from_bytes(rbytes, 'big') # if r >= fieldsize: # return False sbytes = signature[32:] s = int.from_bytes(sbytes, 'big') if s >= order: return False # compressed format, regardless of whether pubkey was compressed or not: pubbytes = point_to_ser(pubpoint, comp=True) ebytes = hashlib.sha256(rbytes + pubbytes + message_hash).digest() e = int.from_bytes(ebytes, 'big') R = s*G + (- e)*pubpoint if R == ecdsa.ellipticcurve.INFINITY: return False if jacobi(R.y(), fieldsize) != 1: return False return (R.x().to_bytes(32, 'big') == rbytes)
def _calc_initial_fast(self): # Fast version of _calc_initial, using libsecp256k1. About 2.4x faster. ctx = seclib.ctx abytes = int(self.a).to_bytes(32, 'big') bbytes = int(self.b).to_bytes(32, 'big') R_buf = create_string_buffer(64) res = seclib.secp256k1_ec_pubkey_parse(ctx, R_buf, self.R, c_size_t(len(self.R))) if not res: raise ValueError('R could not be parsed by the secp256k1 library') pubkey_buf = create_string_buffer(64) res = seclib.secp256k1_ec_pubkey_parse(ctx, pubkey_buf, self.pubkey, c_size_t(len(self.pubkey))) if not res: raise ValueError( 'pubkey could not be parsed by the secp256k1 library') # resave pubkey as compressed. P_compressed = create_string_buffer(33) P_size = c_size_t(33) res = seclib.secp256k1_ec_pubkey_serialize( ctx, P_compressed, byref(P_size), pubkey_buf, secp256k1.SECP256K1_EC_COMPRESSED) self.pubkey_compressed = P_compressed.raw A_buf = create_string_buffer(64) # calculate a*G. ~24 microsec res = seclib.secp256k1_ec_pubkey_create(ctx, A_buf, abytes) assert res == 1, "should never fail since 0 < a < order" # in-place tweak the pubkey by multiplying with scalar b. ~33 microsec res = seclib.secp256k1_ec_pubkey_tweak_mul(ctx, pubkey_buf, bbytes) assert res == 1, "should never fail since 0 < b < order" # add the three points together. ~6 microsec Rnew_buf = create_string_buffer(64) publist = (c_void_p * 3)(*(cast(x, c_void_p) for x in (R_buf, A_buf, pubkey_buf))) res = seclib.secp256k1_ec_pubkey_combine(ctx, Rnew_buf, publist, 3) assert res == 1, "fails with 2^-256 chance (if sum is point at infinity), in which case we have cracked the key" # serialize the new R point Rnew_serialized = create_string_buffer(65) Rnew_size = c_size_t(65) res = seclib.secp256k1_ec_pubkey_serialize( ctx, Rnew_serialized, byref(Rnew_size), Rnew_buf, secp256k1.SECP256K1_EC_UNCOMPRESSED) assert res == 1, "defined to never fail" assert Rnew_size.value == 65, "should fill buffer as uncompressed" self.Rxnew = Rnew_serialized[1:33] y = int.from_bytes(Rnew_serialized[33:], byteorder="big") # calculate the jacobi symbol (+1 or -1). ~30 microsec, because pure python :( self.c = jacobi(y, self.fieldsize)
def sign(privkey, message_hash): '''Create a Schnorr signature. Returns a 64-long bytes object (the signature), or raise ValueError on failure. Failure can occur due to an invalid private key. `privkey` should be the 32 byte raw private key (as you would get from bitcoin.deserialize_privkey, etc). `message_hash` should be the 32 byte sha256d hash of the tx input (or message) you want to sign ''' if not isinstance(privkey, bytes) or len(privkey) != 32: raise ValueError('privkey must be a bytes object of length 32') if not isinstance(message_hash, bytes) or len(message_hash) != 32: raise ValueError('message_hash must be a bytes object of length 32') if _secp256k1_schnorr_sign: sig = create_string_buffer(64) res = _secp256k1_schnorr_sign(secp256k1.secp256k1.ctx, sig, message_hash, privkey, None, None) if not res: # Looking at the libsecp256k1 code, we can see that this will # only occur if privkey is == 0 or >= order, i.e., if it has # no associated pubkey. But as it's not specified in API we'll # just leave it as a vague exception. raise ValueError('could not sign') return bytes(sig) else: # pure python fallback: G = ecdsa.SECP256k1.generator order = G.order() fieldsize = G.curve().p() secexp = int.from_bytes(privkey, 'big') if not 0 < secexp < order: raise ValueError('could not sign') pubpoint = secexp * G pubbytes = point_to_ser(pubpoint, comp=True) k = nonce_function_rfc6979(order, privkey, message_hash, algo16=b'Schnorr+SHA256\x20\x20') R = k * G if jacobi(R.y(), fieldsize) == -1: k = order - k rbytes = int(R.x()).to_bytes(32, 'big') ebytes = hashlib.sha256(rbytes + pubbytes + message_hash).digest() e = int.from_bytes(ebytes, 'big') s = (k + e * secexp) % order return rbytes + int(s).to_bytes(32, 'big')
def psp_2(a_base, pq): p, q = pq[0], pq[1] if p % 4 == 1: # Remark for psp(2,n). Так как ищем для нескольких баз, то учитываем сразу for a in a_base[1:]: if numth.jacobi(q, a) != 1: return False else: continue else: return False return True
def Sign(v, p): if p % 4 == 3: sgm_v_p = [] for a in v: if numth.jacobi(a, p) == 1: sgm_v_p.append(0) elif numth.jacobi(a, p) == -1: sgm_v_p.append(1) return sgm_v_p elif p % 4 == 1: sgm_v_p = [] for a in v: if numth.jacobi(a, p) == -1: val = Val(2, p - 1) sgm_v_p.append(val) else: # print(f'a_base item {a},{p}') ord = Ord(p, a) val = Val(2, ord) sgm_v_p.append(val) return sgm_v_p
def sign(privkey, message_hash): '''Create a Schnorr signature. Returns a 64-long bytes object (the signature), or raise ValueError on failure. Failure can occur due to an invalid private key. `privkey` should be the 32 byte raw private key (as you would get from bitcoin.deserialize_privkey, etc). `message_hash` should be the 32 byte sha256d hash of the tx input (or message) you want to sign ''' if not isinstance(privkey, bytes) or len(privkey) != 32: raise ValueError('privkey must be a bytes object of length 32') if not isinstance(message_hash, bytes) or len(message_hash) != 32: raise ValueError('message_hash must be a bytes object of length 32') G = ecdsa.SECP256k1.generator order = G.order() fieldsize = G.curve().p() secexp = int.from_bytes(privkey, 'big') if not 0 < secexp < order: raise ValueError('could not sign') pubpoint = secexp * G pubbytes = point_to_ser(pubpoint, comp=True) k = nonce_function_rfc6979(order, privkey, message_hash, algo16=b'Schnorr+SHA256\x20\x20') R = k * G if jacobi(R.y(), fieldsize) == -1: k = order - k rbytes = R.x().to_bytes(32,'big') ebytes = hashlib.sha256(rbytes + pubbytes + message_hash).digest() e = int.from_bytes(ebytes, 'big') s = (k + e*secexp) % order return rbytes + s.to_bytes(32, 'big')
def _calc_initial(self): # Internal function, calculates Rxnew, c, and compressed pubkey. try: Rpoint = ser_to_point(self.R) except: # off-curve points, failed decompression, bad format, # point at infinity: raise ValueError('R could not be parsed') try: pubpoint = ser_to_point(self.pubkey) except: # off-curve points, failed decompression, bad format, # point at infinity: raise ValueError('pubkey could not be parsed') self.pubkey_compressed = point_to_ser(pubpoint, comp=True) # multiply & add the points -- takes ~190 microsec Rnew = Rpoint + self.a * ecdsa.SECP256k1.generator + self.b * pubpoint self.Rxnew = int(Rnew.x()).to_bytes(32, 'big') y = Rnew.y() # calculate the jacobi symbol (+1 or -1). ~30 microsec self.c = jacobi(y, self.fieldsize)
def step_t_3(a_base, B): clearfile(f"res/jnd/3/{a_base}/spsp_{B}.txt") clearfile(f"res/jnd/3/{a_base}/n_list_{B}.txt") n_list = [] ### Посчет времени работы start_time = time.time() ### # equal_2_list = parsefile(f"res/jnd/2/{a_base}/n_list_{B}.txt") # упорядочены по возрастанию p1, где p1<p2 # if len(equal_2_list) != 0: # for i in range(len(equal_2_list)): # p1 = equal_2_list[i].primes[0] # p2 = equal_2_list[i].primes[1] # b = int(p1 * p2) for p1 in primes: p1 = int(p1) print(p1) if p1 <= int(root(B, 3)): # and b * p2 < B: if p1 > a_base[-1]: print(p1) s = "" if len(a_base) > 6: a_base = a_base[:6] leg1 = [] for a in a_base: leg1.append(numth.jacobi(a, p1)) p2_3k4 = readfile("primes/4k+3.txt") p2_1k4 = readfile("primes/4k+1.txt") p2_5k8 = readfile("primes/8k+5.txt") p2_1k8 = readfile("primes/8k+1.txt") if p1 % 4 == 3: print(f"p1 34 {p1}") for p2 in p2_3k4: if p2 > p1 and p2 < B and p2 < B: # на всякий случай проверим print(f"p2 34 {p2}") leg2 = [] b = int(p1 * p2) for a in a_base: leg2.append(numth.jacobi(a, p2)) if leg1 == leg2: # Prop.2 inverse is true if b < 2 * 10**6: # a trick gcd_23 = int( gcd(2**(b - 1) - 1, 3**(b - 1) - 1)) factor_list = numth.factorization(gcd_23) for i in range(len(factor_list)): p3 = factor_list[i][0] if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) else: p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) # ищем подходящие p3 if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # continue # новый item из equal_2_list # else: # continue for p2 in p2_1k4: print(f"p2 14 to mu {p2}") if Mu_p(a_base, p2) == 4: pass # переход к mu=4 elif p1 % 8 == 5: print(f"p1 58 {p1}") for p2 in p2_5k8: if p2 > p1 and p2 < B: print(f"p2 58 {p2}") if len(a_base) > 5: a_base = a_base[:5] leg2 = [] b = int(p1 * p2) for a in a_base: leg2.append(numth.jacobi(a, p2)) if leg1 == leg2: p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) print(p3_list, type(p3_list)) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # continue # else: # continue for p2 in p2_1k8: if p2 > p1 and p2 < B: print(f"p2 18 {p2}") if p2 % 16 == 9: print(f"p2 916 {p2}") leg2 = [] b = int(p1 * p2) for a in a_base: leg2.append(numth.jacobi(a, p2)) if np.prod( leg2 ) == 1 and p2 > p1: # если все 1, то произведение 1 p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) else: continue else: continue elif p2 % 16 == 1: print(f"p2 116 to mu {p2}") if Mu_p(a_base, p2) == 4: pass # переход к mu=4 for p2 in p2_3k4: if p2 > p1 and p2 < B: # в тексте этого нет, но на всякий случай проверим print(f"p2 34 {p2}") b = int(p1 * p2) p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) # print(f"p3 list {p3_list}") if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # continue elif p1 % 8 == 1: print(f"p1 18 {p1} p2 any {p2}") e, f = Val(2, p1 - 1), Val(2, Lambda_p(a_base, p1)) if len(a_base) > 5: a_base = a_base[:5] for p2 in primes: if p2 > p1 and p2 < B and e == f: if p2 % (2**(e + 1)) == (1 + 2**e) % (2**( e + 1)): # !!!! СКОБКИ??? leg2 = [] b = int(p1 * p2) for a in a_base: leg2.append(numth.jacobi(a, p2)) if leg1 == leg2: p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) else: continue else: continue elif p2 % (2**(e + 2)) == 1: if Mu_p(a_base, p2) == 4: pass # переход к mu=4 elif p2 % (2**(e + 2)) != 1 and p2 % (2**( e + 2)) == (1 + 2**(e + 1)) % 2**( e + 2): # !!!! СКОБКИ??? leg2 = [] b = int(p1 * p2) for a in a_base: leg2.append(numth.jacobi(a, p2)) if np.prod(leg2) == 1: p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) else: continue else: continue elif p2 > p1 and p2 < B and f < e: if p2 % 2**f == p1: if f == e - 1 and Mu_p( a_base, p1) == 2: # это есть условие выше p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) b = int(p1 * p2) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs( a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) else: continue else: continue else: continue # p1 is any in primes mu_4 = readfile(f"lib/mu/{a_base}/mu_4.txt") for p2 in mu_4: if p2 > p1 and p2 < B: # если p2 mu=4, то не обязательно чтобы и p1 mu=4 print(f"p2 mu4 {p2}") p_exist = np.array([p1, p2]) p3_list = next_p(p_exist, a_base, B) b = int(p1 * p2) if isinstance(p3_list, list) and len(p3_list) != 0: for p3 in p3_list: if p3 * b <= B: # and p3 * b > B // 100: if p3 > p2: print(f"p3 {p3}") signss = check_signs(a_base, [p1, p3]) if signss: item = Signature( Sign(a_base, p1), [p1, p2, p3]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # continue writefile(f"res/jnd/3/{a_base}/n_list_{B}.txt", s) else: continue else: break i = 1 spsp = [] ss = "" for item in n_list: prod = np.prod(item.primes) if psp(a_base, prod): ss += f"{i} {prod} {item.primes} {item.sign}\n" i += 1 spsp.append(item) ### total_time = "--- %s seconds ---\n" % (time.time() - start_time) ### ss += f"{total_time}\n" writefile(f"res/jnd/3/{a_base}/spsp_{B}.txt", ss) return np.array(spsp)
def step_t_2(a_base, B, primes_list): clearfile(f"res/jnd/2/{a_base}/spsp_{B}.txt") clearfile(f"res/jnd/2/{a_base}/n_list_{B}.txt") n_list = [] ### Посчет времени работы start_time = time.time() ### for p1 in primes_list: p1 = int(p1) if p1 < int(root(B, 2)): if p1 > a_base[-1]: s = "" if p1 < 10**6: gcd_23 = int(gcd(2**(p1 - 1) - 1, 3**(p1 - 1) - 1)) factors = sorted(numth.factorization(gcd_23)) for i in range(len(factors)): p2 = factors[i][0] if p2 * p1 <= B: # and p1 * p2 > B // 100: if p2 > p1: # В дальнейшем для того, чтобы числа в интервалах не повторялись signss = check_signs(a_base, [p1, p2]) if signss: item = Signature(Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break elif p1 > 10**8: lmd_p = Lambda_p(a_base, p1) # lmd_p = p1-1 p2 = 1 while p2 <= p1: # and p1 * p2 > B // 100: # к условию, что p2>p1 p2 += lmd_p while p2 * p1 <= B: # and p1 * p2 > B // 100: signss = check_signs(a_base, [p1, p2]) if signss: item = Signature(Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(Signature(item.sign, [p1, p2])) p2 += lmd_p else: # между 10**6..10**8 if len(a_base) > 6: a_base = a_base[:6] lmd_p = Lambda_p(a_base, p1) leg1 = [] for a in a_base: leg1.append(numth.jacobi(a, p1)) if p1 % 4 == 1: p2_4k3 = readfile("primes/4k+3.txt") p2_4k1 = readfile("primes/4k+1.txt") for p2 in p2_4k3: if p1 * p2 <= B: # and p1 * p2 > B // 100: if p2 % lmd_p == 1 and p2 > p1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if leg1 == leg2 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break for p2 in p2_4k1: if p1 * p2 <= B: # and p1 * p2 > B // 100: if p2 % lmd_p == 1 and p2 > p1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if np.prod( leg2 ) == 1 and signss: # если все 1, то произведение 1 item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break elif p1 % 8 == 5: p2_8k5 = readfile("primes/8k+5.txt") p2_8k1 = readfile("primes/8k+1.txt") for p2 in p2_8k5: if p1 * p2 <= B: # and p1 * p2 > B // 100: if p2 % lmd_p == 5 and p2 > p1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if leg1 == leg2 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break for p2 in p2_8k1: if p1 * p2 <= B: # and p1 * p2 > B // 100: if p2 % lmd_p == 1 and p2 > p1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if np.prod(leg2) == 1 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break elif p1 % 8 == 1: sign = Sign([2], p1)[0] e, f = Val(2, p1 - 1), Val(2, sign) for p2 in primes: if p1 * p2 <= B: # and p1 * p2 > B // 100: if p2 > p1 and e == f: if p2 % (2**(e - 1)) == 2**e % (2**( e - 1)) and p2 % lmd_p == 1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if leg1 == leg2 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) elif p2 % 2**(e + 1) == 1 and p2 % lmd_p == 1: leg2 = [] for a in a_base: leg2.append(numth.jacobi(a, p2)) signss = check_signs(a_base, [p1, p2]) if np.prod(leg2) == 1 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) elif p2 > p1 and f < e and p1 * p2 <= B: # and p1 * p2 > B // 100: signss = check_signs(a_base, [p1, p2]) if p2 % lmd_p == 1 and signss: item = Signature( Sign(a_base, p1), [p1, p2]) s += f"{item.primes} {signss} {item.sign}\n" n_list.append(item) # else: # break writefile(f"res/jnd/2/{a_base}/n_list_{B}.txt", s) else: continue i = 1 spsp = [] ss = "" for item in n_list: prod = np.prod(item.primes) if psp(a_base, prod): ss += f"{i} {prod} {item.primes} {item.sign}\n" i += 1 spsp.append(item) ### total_time = "--- %s seconds ---\n" % (time.time() - start_time) ### ss += f"{total_time}\n" writefile(f"res/jnd/2/{a_base}/spsp_{B}.txt", ss) return np.array(spsp)