def test_batch_validation(self): hsize = hf().digest_size hlen = hsize * 8 ms = [] Qs = [] sigs = [] ms.append(secrets.randbits(hlen).to_bytes(hsize, 'big')) q = 1 + secrets.randbelow(ec.n - 1) # bytes version Qs.append(mult(q, ec.G, ec)[0].to_bytes(ec.psize, 'big')) sigs.append(ssa.sign(ms[0], q, None, ec, hf)) # test with only 1 sig ssa._batch_verify(ms, Qs, sigs, ec, hf) for _ in range(3): mhd = secrets.randbits(hlen).to_bytes(hsize, 'big') ms.append(mhd) q = 1 + secrets.randbelow(ec.n - 1) # Point version Qs.append(mult(q, ec.G, ec)) sigs.append(ssa.sign(mhd, q, None, ec, hf)) ssa._batch_verify(ms, Qs, sigs, ec, hf) self.assertTrue(ssa.batch_verify(ms, Qs, sigs, ec, hf)) # invalid sig ms.append(ms[0]) sigs.append(sigs[1]) Qs.append(Qs[0]) self.assertFalse(ssa.batch_verify(ms, Qs, sigs, ec, hf)) self.assertRaises(AssertionError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs[-1] = sigs[0] # valid again # Invalid size: 31 bytes instead of 32 ms[-1] = ms[0][:-1] self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) ms[-1] = ms[0] # valid again # mismatch between number of pubkeys (5) and number of messages (6) ms.append(ms[0]) # add extra message self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) ms.pop() # valid again # mismatch between number of pubkeys (5) and number of signatures (6) sigs.append(sigs[0]) # add extra sig self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf) # ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs.pop() # valid again # field prime p is not equal to 3 (mod 4) self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, secp224k1, hf)
def test_batch_validation() -> None: ms: List[String] = [] Qs: List[int] = [] sigs: List[ssa.SSASig] = [] err_msg = "no signatures provided" with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_batch_as_valid(ms, Qs, sigs) assert not ssa.batch_verify(ms, Qs, sigs) # valid size for String input to sign, not for Octets input to _sign msg_size = 16 ms.append(secrets.token_bytes(msg_size)) q, Q = ssa.gen_keys() Qs.append(Q) sigs.append(ssa.sign(ms[0], q)) # test with only 1 sig ssa.assert_batch_as_valid(ms, Qs, sigs) assert ssa.batch_verify(ms, Qs, sigs) for _ in range(3): m = secrets.token_bytes(msg_size) ms.append(m) q, Q = ssa.gen_keys() Qs.append(Q) sigs.append(ssa.sign(m, q)) ssa.assert_batch_as_valid(ms, Qs, sigs) assert ssa.batch_verify(ms, Qs, sigs) ms.append(ms[0]) sigs.append(sigs[1]) Qs.append(Qs[0]) err_msg = "signature verification failed" with pytest.raises(BTClibRuntimeError, match=err_msg): ssa.assert_batch_as_valid(ms, Qs, sigs) assert not ssa.batch_verify(ms, Qs, sigs) sigs[-1] = sigs[0] # valid again ms.append(ms[0]) # add extra message err_msg = "mismatch between number of pubkeys " with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_batch_as_valid(ms, Qs, sigs) assert not ssa.batch_verify(ms, Qs, sigs) ms.pop() # valid again sigs.append(sigs[0]) # add extra sig err_msg = "mismatch between number of pubkeys " with pytest.raises(BTClibValueError, match=err_msg): ssa.assert_batch_as_valid(ms, Qs, sigs) assert not ssa.batch_verify(ms, Qs, sigs) sigs.pop() # valid again ms = [reduce_to_hlen(m, hf) for m in ms] ms[0] = ms[0][:-1] err_msg = "invalid size: 31 bytes instead of 32" with pytest.raises(BTClibValueError, match=err_msg): ssa._assert_batch_as_valid(ms, Qs, sigs) assert not ssa._batch_verify(ms, Qs, sigs)
def test_batch_validation() -> None: ec = CURVES["secp256k1"] hsize = hf().digest_size hlen = hsize * 8 ms = [] Qs = [] sigs = [] ms.append(secrets.randbits(hlen).to_bytes(hsize, "big")) q = 1 + secrets.randbelow(ec.n - 1) # bytes version Qs.append(mult(q, ec.G, ec)[0]) sigs.append(ssa._sign(ms[0], q, None, ec, hf)) # test with only 1 sig ssa._batch_verify(ms, Qs, sigs, ec, hf) for _ in range(3): m = secrets.randbits(hlen).to_bytes(hsize, "big") ms.append(m) q = 1 + secrets.randbelow(ec.n - 1) # Point version Qs.append(mult(q, ec.G, ec)[0]) sigs.append(ssa._sign(m, q, None, ec, hf)) ssa._batch_verify(ms, Qs, sigs, ec, hf) assert ssa.batch_verify(ms, Qs, sigs, ec, hf) ms.append(ms[0]) sigs.append(sigs[1]) Qs.append(Qs[0]) assert not ssa.batch_verify(ms, Qs, sigs, ec, hf) err_msg = "signature verification precondition failed" with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs[-1] = sigs[0] # valid again ms[-1] = ms[0][:-1] err_msg = "invalid size: 31 bytes instead of 32" with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) ms[-1] = ms[0] # valid again ms.append(ms[0]) # add extra message err_msg = "mismatch between number of pubkeys " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) ms.pop() # valid again sigs.append(sigs[0]) # add extra sig err_msg = "mismatch between number of pubkeys " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, ec, hf) sigs.pop() # valid again err_msg = "field prime is not equal to 3 mod 4: " with pytest.raises(ValueError, match=err_msg): ssa._batch_verify(ms, Qs, sigs, CURVES["secp224k1"], hf)
hsize = hf().digest_size hlen = hsize * 8 # n = 1 loops forever and does not really test batch verify n_sig = [4, 8, 16, 32, 64, 128, 256, 512] m = [ random.getrandbits(hlen).to_bytes(hsize, "big") for _ in range(max(n_sig)) ] q = [random.getrandbits(ec.nlen) % ec.n for _ in m] sig = [_sign(msg, qq) for msg, qq in zip(m, q)] Q = [mult(qq, ec.G)[0] for qq in q] for n in n_sig: # no batch start = time.time() for j in range(n): assert _verify(m[j], Q[j], sig[j]) elapsed1 = time.time() - start # batch ms = m[:n] Qs = Q[:n] sigs = sig[:n] start = time.time() assert _batch_verify(ms, Qs, sigs), n elapsed2 = time.time() - start print(n, elapsed2 / elapsed1)