Exemple #1
0
 def create_state(self, params, seed, which):
     self.multipliers, self.ph, self.params = params
     self.state = FFI.new("struct umash_state[1]")
     self.sink = FFI.addressof(self.state[0].sink)
     C.umash_init(self.state, self.params, seed, which)
     self.seed = seed
     self.which = which
Exemple #2
0
def test_public_params_derive(bits, key):
    length = FFI.sizeof("struct umash_params")

    umash_key = b"Do not use UMASH VS adversaries."
    if key is not None:
        umash_key = key
    nonce = struct.pack("<Q", bits)

    expected = FFI.new("struct umash_params[1]")
    salsa_bytes = Salsa20.new(umash_key, nonce).encrypt(b"\x00" * length)
    FFI.memmove(expected, salsa_bytes, length)
    assert C.umash_params_prepare(expected)

    actual = FFI.new("struct umash_params[1]")
    if key is None:
        C.umash_params_derive(actual, bits, FFI.NULL)
    else:
        buf = FFI.new("char[]", len(key))
        FFI.memmove(buf, key, len(key))
        C.umash_params_derive(actual, bits, buf)

    # The values should all be the same.
    assert length % 8 == 0
    for i in range(length // 8):
        assert FFI.cast("uint64_t *",
                        actual)[i] == FFI.cast("uint64_t *", expected)[i]
def test_public_smoke_matches(random, seed, data):
    """Prepare a params struct, and make sure the UMASH function matches
    our reference."""
    params = FFI.new("struct umash_params[1]")
    size = FFI.sizeof("struct umash_params")
    assert size % 8 == 0
    for i in range(size // 8):
        FFI.cast("uint64_t *", params)[i] = random.getrandbits(64)

    # Pseudorandom input should always succeed.
    assert C.umash_params_prepare(params) == True
    assert_idempotent(params)
    expected0 = umash(
        UmashKey(params[0].poly[0][1],
                 [params[0].oh[i] for i in range(OH_COUNT)]),
        seed,
        data,
        secondary=False,
    )
    assert C.umash_full(params, seed, 0, data, len(data)) == expected0

    expected1 = umash(
        UmashKey(
            params[0].poly[1][1],
            [params[0].oh[i] for i in range(OH_COUNT)],
        ),
        seed,
        data,
        secondary=True,
    )
    assert C.umash_full(params, seed, 1, data, len(data)) == expected1
Exemple #4
0
def test_vec_to_u64(data):
    """Make sure we expand to a uint64 correctly."""
    n_bytes = len(data)
    # Copy to a malloc-ed buffer to help ASan.
    buf = FFI.new("char[]", n_bytes)
    FFI.memmove(buf, data, n_bytes)
    assert C.vec_to_u64(buf, n_bytes) == vec_to_u64(data)
Exemple #5
0
def test_umash_short(seed, key, data):
    """Compare umash_short with the reference."""
    expected = umash(UmashKey(poly=0, oh=key), seed, data)

    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].oh[i] = param

    assert C.umash_short(params[0].oh, seed, block, n_bytes) == expected
def assert_idempotent(params):
    """Asserts that calling `umash_params_prepare` on something that was
    successfully prepared is idempotent.
    """
    size = FFI.sizeof("struct umash_params")
    copy = FFI.new("struct umash_params[1]")
    FFI.memmove(copy, params, size)
    assert C.umash_params_prepare(copy) == True
    # The copy should still be the same as params.
    assert size % 8 == 0
    for i in range(size // 8):
        assert FFI.cast("uint64_t *",
                        params)[i] == FFI.cast("uint64_t *", copy)[i]
Exemple #7
0
def test_public_umash_full(seed, multiplier, key, data):
    """Compare umash_full with the reference."""
    expected = umash(UmashKey(poly=multiplier, ph=key), seed, data)

    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    params = FFI.new("struct umash_params[1]")
    params[0].poly[0][0] = (multiplier ** 2) % FIELD
    params[0].poly[0][1] = multiplier
    for i, param in enumerate(key):
        params[0].ph[i] = param

    assert C.umash_full(params, seed, 0, block, n_bytes) == expected
Exemple #8
0
def test_public_umash_full_shifted(seed, multiplier, key, data):
    """Compare umash_full(which=1) with the reference."""
    expected = umash(UmashKey(poly=multiplier, oh=key), seed, data)

    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    params = FFI.new("struct umash_params[1]")
    params[0].poly[1][0] = (multiplier**2) % FIELD
    params[0].poly[1][1] = multiplier
    for i, param in enumerate(key):
        params[0].oh[i + C.UMASH_OH_TOEPLITZ_SHIFT] = param

    assert C.umash_full(params, seed, 1, block, n_bytes) == expected
Exemple #9
0
def test_umash_medium(seed, multiplier, key, data):
    """Compare umash_medium with the reference."""
    expected = umash(UmashKey(poly=multiplier, ph=key), seed, data)

    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    poly = FFI.new("uint64_t[2]")
    poly[0] = (multiplier**2) % FIELD
    poly[1] = multiplier
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].ph[i] = param

    assert C.umash_medium(poly, params[0].ph, seed, block, n_bytes) == expected
Exemple #10
0
def test_umash_long_repeat(seed, multiplier, key, data):
    """Compare umash_long on repeated strings with the reference."""
    expected = umash(UmashKey(poly=multiplier, oh=key), seed, data, secondary=False)
    note(len(data))

    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    poly = FFI.new("uint64_t[2]")
    poly[0] = (multiplier ** 2) % FIELD
    poly[1] = multiplier
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].oh[i] = param

    assert C.umash_long(poly, params[0].oh, seed, block, n_bytes) == expected
Exemple #11
0
def test_ph_one_block(seed, key, data):
    """Compare PH compression for full blocks."""
    expected = ph_compress_one_block(key, seed, split_block(data))

    # Copy to exactly-sized malloced buffers to help ASan.
    block = FFI.new("char[]", BLOCK_SIZE)
    FFI.memmove(block, data, BLOCK_SIZE)
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].ph[i] = param

    actual = C.ph_one_block(params[0].ph, seed, block)
    assert expected == actual.bits[0] + (actual.bits[1] << 64), (
        actual.bits[0],
        actual.bits[1],
    )
Exemple #12
0
def test_oh_one_block(tag, key, data):
    """Compare OH compression for full blocks."""
    # The C-side implicit accepts the high half of the tag, and leaves
    # the low half zeroed out.
    expected = oh_compress_one_block(key, split_block(data), tag << 64)

    # Copy to exactly-sized malloced buffers to help ASan.
    block = FFI.new("char[]", BLOCK_SIZE)
    FFI.memmove(block, data, BLOCK_SIZE)
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].oh[i] = param

    actual = C.oh_one_block(params[0].oh, tag, block)
    assert expected == actual.bits[0] + (actual.bits[1] << 64), (
        actual.bits[0],
        actual.bits[1],
    )
Exemple #13
0
def test_public_umash_fprint(seed, multipliers, key, data):
    """Compare umash_fprint with two calls to the reference."""
    expected = [
        umash(UmashKey(poly=multipliers[0], oh=key[:-4]), seed, data),
        umash(UmashKey(poly=multipliers[1], oh=key[4:]), seed, data),
    ]
    n_bytes = len(data)
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    params = FFI.new("struct umash_params[1]")
    for i, multiplier in enumerate(multipliers):
        params[0].poly[i][0] = (multiplier**2) % FIELD
        params[0].poly[i][1] = multiplier
    for i, param in enumerate(key):
        params[0].oh[i] = param

    actual = C.umash_fprint(params, seed, block, n_bytes)
    assert [actual.hash[0], actual.hash[1]] == expected
Exemple #14
0
def test_ph_tail_large(seed, key, data):
    """Compare PH compression for the last block, when it has enough data
    to fully contain the last 16-byte chunk."""
    expected = ph_compress_one_block(key, seed, split_block(data))

    n_bytes = len(data)
    # Copy to exactly-sized malloced buffers to help ASan.
    block = FFI.new("char[]", n_bytes)
    FFI.memmove(block, data, n_bytes)
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].ph[i] = param

    actual = C.ph_last_block(params[0].ph, seed, block, n_bytes)
    assert expected == actual.bits[0] + (actual.bits[1] << 64), (
        actual.bits[0],
        actual.bits[1],
    )
Exemple #15
0
def test_ph_tail_short(seed, key, prefix, data):
    """Compare PH compression for the last block, when we must steal some
    data from the previous chunk."""
    expected = ph_compress_one_block(
        key, seed, split_block(prefix * (C.UMASH_PH_PARAM_COUNT // 2) + data)
    )

    offset = len(prefix)
    n_bytes = len(data)
    # Copy to exactly-sized malloced buffers to help ASan.
    block = FFI.new("char[]", offset + n_bytes)
    FFI.memmove(block, prefix + data, offset + n_bytes)
    params = FFI.new("struct umash_params[1]")
    for i, param in enumerate(key):
        params[0].ph[i] = param

    actual = C.ph_last_block(params[0].ph, seed, block + offset, n_bytes)
    assert expected == actual.bits[0] + (actual.bits[1] << 64), (
        actual.bits[0],
        actual.bits[1],
    )
def test_public_bad_oh(oh, random):
    """When the OH values repeat, we should replace them if we can.
    """
    repeated_values = len(oh) - len(set(oh))

    params = FFI.new("struct umash_params[1]")
    for i in range(2):
        params[0].poly[i][0] = random.getrandbits(64)
        params[0].poly[i][1] = random.getrandbits(64)

    for i, value in enumerate(oh):
        params[0].oh[i] = value

    result = C.umash_params_prepare(params)
    if repeated_values > 2:
        assert result == False
    if not result:
        return

    assert_idempotent(params)
    # On success, the OH parameters should be unique
    actual_oh = [params[0].oh[i] for i in range(OH_COUNT)]
    assert len(actual_oh) == len(set(actual_oh))
def test_public_multiplier_reduction(multipliers, random):
    """Make sure multipliers are correctly reduced and rejected."""
    params = FFI.new("struct umash_params[1]")
    params[0].poly[0][0] = random.getrandbits(64)
    params[0].poly[0][1] = multipliers[0]
    params[0].poly[1][0] = random.getrandbits(64)
    params[0].poly[1][1] = multipliers[1]

    for i in range(OH_COUNT):
        params[0].oh[i] = i

    assert C.umash_params_prepare(params) == True
    assert_idempotent(params)
    for i in range(2):
        # If we passed in something clearly usable, it should be kept.
        if 0 < multipliers[i] < FIELD:
            assert params[0].poly[i][1] == multipliers[i]
        # The multipliers must be valid.
        assert 0 < params[0].poly[i][1] < FIELD
        assert params[0].poly[i][0] == (params[0].poly[i][1]**2) % FIELD

    # The OH params are valid.
    for i in range(C.UMASH_OH_PARAM_COUNT + C.UMASH_OH_TWISTING_COUNT):
        assert params[0].oh[i] == i
 def create_state(self, params, seed):
     self.multipliers, self.oh, self.params = params
     self.state = FFI.new("struct umash_fp_state[1]")
     self.sink = FFI.addressof(self.state[0].sink)
     C.umash_fp_init(self.state, self.params, seed)
     self.seed = seed
Exemple #19
0
def test_add_mod_fast_general(x, y):
    """Exercise the fast modular addition interface's claimed precondition."""
    assume(x + y < 2**65 - 8)
    assert C.add_mod_fast(x, y) % MODULO == (x + y) % MODULO
Exemple #20
0
def test_add_mod_slow(x, y):
    """Make sure the result of `add_mod_slow` is fully reduced."""
    assert C.add_mod_slow(x, y) == (x + y) % MODULO
Exemple #21
0
def test_finalize(x):
    assert C.finalize(x) == finalize(x)
Exemple #22
0
def test_mul_mod_fast_general(m, x):
    """Check fast modular multiplication, for the case we about."""
    assume(m * x < 2**125)
    assert C.mul_mod_fast(m, x) % MODULO == (m * x) % MODULO
Exemple #23
0
 def digest_value(self):
     result = C.umash_fp_digest(self.state)
     return [result.hash[0], result.hash[1]]
Exemple #24
0
 def batch_value(self):
     result = C.umash_fprint(self.params, self.seed, self.acc,
                             len(self.acc))
     return [result.hash[0], result.hash[1]]
Exemple #25
0
 def update(self, buf, n):
     C.umash_sink_update(self.sink, buf, n)
Exemple #26
0
 def digest_value(self):
     return C.umash_digest(self.state)
Exemple #27
0
 def batch_value(self):
     return C.umash_full(self.params, self.seed, self.which, self.acc,
                         len(self.acc))
Exemple #28
0
def test_horner_double_update(acc, m0, m1, x, y):
    expected = (m0 * (acc + x) + m1 * y) % MODULO
    assert C.horner_double_update(acc, m0, m1, x, y) == expected
Exemple #29
0
def test_salsa20(length, nonce, key):
    expected = Salsa20.new(key, nonce).encrypt(b"\x00" * length)
    buf = FFI.new("char[]", length)
    C.salsa20_stream(buf, length, nonce, key)
    assert bytes(FFI.buffer(buf, length)) == expected
Exemple #30
0
def test_add_mod_fast(x, y):
    """Check fast modular addition, for the case we care in practice."""
    assert C.add_mod_fast(x, y) % MODULO == (x + y) % MODULO