Skip to content
This repository was archived by the owner on Sep 3, 2025. It is now read-only.
This repository was archived by the owner on Sep 3, 2025. It is now read-only.

OKVS with u64 arithmetic add #86

@lzjluzijie

Description

@lzjluzijie

I'm trying to use OKVS for u64 type. The default helper works normally with xor operation of u64:

using ValueType = u64;

template<typename T>
struct Helper {
  using value_type = T;
  using iterator = T *;
  using const_iterator = const T *;

  // mutable version of value_type
  using mut_value_type = std::remove_const_t<value_type>;
  using mut_iterator = mut_value_type *;

  // internal mask used to multiply a value with a bit.
  // Assumes the zero bit string is the zero element.
  std::array<mut_value_type, 2> zeroOneMask;

  Helper() {
    memset(&zeroOneMask[0], 0, sizeof(T));
    memset(&zeroOneMask[1], -1, sizeof(T));
  }

  Helper(const Helper &) = default;

  // return a element that the user can use.
  inline static mut_value_type newElement() { return {}; }

  // return the iterator for the return type of newElement().
  mut_iterator asPtr(mut_value_type &t) { return &t; }

  // return a vector of elements that the user can use.
  inline static PxVector<mut_value_type> newVec(u64 size) { return {size}; }

  // assign the src to the dst, ie *dst = *src.
  inline static void assign(mut_iterator dst, const_iterator src) { *dst = *src; }

  // add the src to the dst, ie *dst += *src.
  inline static void add(mut_iterator dst, const_iterator src1) { *dst = *dst ^ *src1; }

  // multiply src1 with m and add the result to the dst, ie *dst += (*src) * m.
  inline static void multAdd(mut_iterator dst, const_iterator src1, const block &m) {
    if constexpr (std::is_same<block, mut_value_type>::value)
      *dst = *dst ^ src1->gf128Mul(m);
    else
      throw std::runtime_error("the gf128 dense encoding is only implemented for block type. " LOCATION);
  }

  // multiply src1 with bit and add the result to the dst, ie *dst += (*src) * bit.
  inline void multAdd(mut_iterator dst, const_iterator src1, const u8 &bit) {
    assert(bit < 2);
    *dst = *dst ^ (*src1 & zeroOneMask[bit]);
  }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(const_iterator p, u64 i) { return p + i; }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(mut_iterator p, u64 i) { return p + i; }

  // randomize the given element.
  inline static void randomize(mut_iterator p, oc::PRNG &prng) {
    prng.get(p, 1);
  }


  inline static auto eq(iterator p0, iterator p1) {
    return *p0 == *p1;
  }
};

void paxos() {
  u64 n = 1 << 15;
  u64 w = 3;

  PRNG prng(oc::sysRandomSeed());
  block seed1 = prng.get();

  Helper<ValueType> helper;

  Paxos<u32> paxos;
  Paxos<u32> paxos2;
  paxos.init(n, w, 40, PaxosParam::Binary, seed1);
  paxos2.init(n, w, 40, PaxosParam::Binary, seed1);

  std::vector<block> items(n);
  std::vector<ValueType> values0(n), values1(n), values2(n);
  std::vector<ValueType> p0(paxos.size()), p1(paxos.size()), p2(paxos.size());

  prng.get(items.data(), items.size());
  prng.get(values0.data(), values0.size());
  prng.get(values1.data(), values1.size()); {
    paxos.setInput(items);
    PxVector<const ValueType> V(values0);
    PxVector<ValueType> P(p0);
    paxos.encode(V, P, helper, nullptr);
  } {
    paxos.setInput(items);
    PxVector<const ValueType> V(values1);
    PxVector<ValueType> P(p1);
    paxos.encode(V, P, helper, nullptr);
  }

  u64 lim = 227;
  for (u64 i = 0; i < lim; i++) {
    items[i] = prng.get();
  }
  for (u64 i = 0; i < paxos.size(); i++) {
    p2[i] = p0[i] ^ p1[i];
  }
  paxos2.decode<ValueType>(items, values2, p2);

  for (u64 i = 0; i < n; i++) {
    if (i < lim) {
      if (values2[i] == (values0[i] ^ values1[i])) {
        throw RTE_LOC;
      }
    } else {
      if ((values0[i] ^ values1[i]) != values2[i]) {
        std::printf("%lu\n", i);
        throw RTE_LOC;
      }
    }
  }

  std::printf("paxos ok\n");
}

However, I try to use the arithmetic add, the code didn't work:

using ValueType = u64;

template<typename T>
struct Helper {
  using value_type = T;
  using iterator = T *;
  using const_iterator = const T *;

  // mutable version of value_type
  using mut_value_type = std::remove_const_t<value_type>;
  using mut_iterator = mut_value_type *;

  // return a element that the user can use.
  inline static mut_value_type newElement() { return {}; }

  // return the iterator for the return type of newElement().
  mut_iterator asPtr(mut_value_type &t) { return &t; }

  // return a vector of elements that the user can use.
  inline static PxVector<mut_value_type> newVec(u64 size) { return {size}; }

  // assign the src to the dst, ie *dst = *src.
  inline static void assign(mut_iterator dst, const_iterator src) { *dst = *src; }

  // add the src to the dst, ie *dst += *src.
  inline static void add(mut_iterator dst, const_iterator src1) { *dst = *dst + *src1; }

  // multiply src1 with m and add the result to the dst, ie *dst += (*src) * m.
  inline static void multAdd(mut_iterator dst, const_iterator src1, const block &m) {
    throw std::runtime_error("the gf128 dense encoding is only implemented for block type. " LOCATION);
  }

  // multiply src1 with bit and add the result to the dst, ie *dst += (*src) * bit.
  inline void multAdd(mut_iterator dst, const_iterator src1, const u8 &bit) {
    assert(bit < 2);
    *dst = *dst + (*src1 * bit);
  }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(const_iterator p, u64 i) { return p + i; }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(mut_iterator p, u64 i) { return p + i; }

  // randomize the given element.
  inline static void randomize(mut_iterator p, oc::PRNG &prng) {
    prng.get(p, 1);
  }

  inline static auto eq(iterator p0, iterator p1) {
    return *p0 == *p1;
  }
};

void paxos() {
  u64 n = 1 << 15;
  u64 w = 3;

  PRNG prng(oc::sysRandomSeed());
  block seed1 = prng.get();

  Helper<ValueType> helper;

  Paxos<u32> paxos;
  Paxos<u32> paxos2;
  paxos.init(n, w, 40, PaxosParam::Binary, seed1);
  paxos2.init(n, w, 40, PaxosParam::Binary, seed1);

  std::vector<block> items(n);
  std::vector<ValueType> values0(n), values1(n), values2(n);
  std::vector<ValueType> p0(paxos.size()), p1(paxos.size()), p2(paxos.size());

  prng.get(items.data(), items.size());
  prng.get(values0.data(), values0.size());
  prng.get(values1.data(), values1.size());

  // encode p0
  {
    paxos.setInput(items);
    PxVector<const ValueType> V(values0);
    PxVector<ValueType> P(p0);
    paxos.encode(V, P, helper, nullptr);
  }

  // encode p1
  {
    paxos.setInput(items);
    PxVector<const ValueType> V(values1);
    PxVector<ValueType> P(p1);
    paxos.encode(V, P, helper, nullptr);
  }

  u64 lim = 227;
  for (u64 i = 0; i < lim; i++) {
    items[i] = prng.get();
  }
  for (u64 i = 0; i < paxos.size(); i++) {
    p2[i] = p0[i] + p1[i];
  }
  paxos2.decode<ValueType>(items, values2, p2);

  for (u64 i = 0; i < n; i++) {
    if (i < lim) {
      if (values2[i] == (values0[i] + values1[i])) {
        throw RTE_LOC;
      }
    } else {
      if ((values0[i] + values1[i]) != values2[i]) {
        std::printf("%lu\n", i);
        throw RTE_LOC;
      }
    }
  }

  std::printf("paxos ok\n");
}

as we got values0[i] + values1[i]) != values2[i]. I think the OKVS requires the ValueType to be a field, so I also tried prime field:

u64 p = 10007;
using ValueType = u64;

template<typename T>
struct Helper {
  using value_type = T;
  using iterator = T *;
  using const_iterator = const T *;

  // mutable version of value_type
  using mut_value_type = std::remove_const_t<value_type>;
  using mut_iterator = mut_value_type *;

  // return a element that the user can use.
  inline static mut_value_type newElement() { return {}; }

  // return the iterator for the return type of newElement().
  mut_iterator asPtr(mut_value_type &t) { return &t; }

  // return a vector of elements that the user can use.
  inline static PxVector<mut_value_type> newVec(u64 size) { return {size}; }

  // assign the src to the dst, ie *dst = *src.
  inline static void assign(mut_iterator dst, const_iterator src) { *dst = *src; }

  // add the src to the dst, ie *dst += *src.
  inline static void add(mut_iterator dst, const_iterator src1) { *dst = (*dst + *src1) % p; }

  // multiply src1 with m and add the result to the dst, ie *dst += (*src) * m.
  inline static void multAdd(mut_iterator dst, const_iterator src1, const block &m) {
    throw std::runtime_error("the gf128 dense encoding is only implemented for block type. " LOCATION);
  }

  // multiply src1 with bit and add the result to the dst, ie *dst += (*src) * bit.
  inline void multAdd(mut_iterator dst, const_iterator src1, const u8 &bit) {
    assert(bit < 2);
    *dst = (*dst + (*src1 * bit)) % p;
  }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(const_iterator p, u64 i) { return p + i; }

  // return the iterator plus the given number of rows
  inline static auto iterPlus(mut_iterator p, u64 i) { return p + i; }

  // randomize the given element.
  inline static void randomize(mut_iterator p, oc::PRNG &prng) {
    prng.get(p, 1);
  }

  inline static auto eq(iterator p0, iterator p1) {
    return (*p0 % p) == (*p1 % p);
  }
};

void paxos() {
  u64 n = 1 << 15;
  u64 w = 3;

  PRNG prng(oc::sysRandomSeed());
  block seed1 = prng.get();

  Helper<ValueType> helper;

  Paxos<u32> paxos;
  Paxos<u32> paxos2;
  paxos.init(n, w, 40, PaxosParam::Binary, seed1);
  paxos2.init(n, w, 40, PaxosParam::Binary, seed1);

  std::vector<block> items(n);
  std::vector<ValueType> values0(n), values1(n), values2(n);
  std::vector<ValueType> p0(paxos.size()), p1(paxos.size()), p2(paxos.size());

  prng.get(items.data(), items.size());
  prng.get(values0.data(), values0.size());
  prng.get(values1.data(), values1.size());

  for (u64 i = 0; i < n; i++) {
    values0[i] = values0[i] % p;
    values1[i] = values1[i] % p;
  }

  // encode p0
  {
    paxos.setInput(items);
    PxVector<const ValueType> V(values0);
    PxVector<ValueType> P(p0);
    paxos.encode(V, P, helper, nullptr);
  }

  // encode p1
  {
    paxos.setInput(items);
    PxVector<const ValueType> V(values1);
    PxVector<ValueType> P(p1);
    paxos.encode(V, P, helper, nullptr);
  }

  u64 lim = 227;
  for (u64 i = 0; i < lim; i++) {
    items[i] = prng.get();
  }
  for (u64 i = 0; i < paxos.size(); i++) {
    p2[i] = (p0[i] + p1[i]) % p;
  }
  paxos2.decode<ValueType>(items, values2, p2);

  for (u64 i = 0; i < n; i++) {
    if (i < lim) {
      if ((values2[i] % p) == ((values0[i] + values1[i]) % p)) {
        throw RTE_LOC;
      }
    } else {
      if (((values0[i] + values1[i]) % p) != (values2[i] % p)) {
        std::printf("%lu\n", i);
        throw RTE_LOC;
      }
    }
  }

  std::printf("paxos ok\n");
}

But I got the same error. I think I might be missing the inverse part, but the helper does not have a inverse function. Could you give me some instructions. Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions