|
@@ -1,6 +1,8 @@
|
|
|
#ifndef __DUORAM_HPP__
|
|
|
#define __DUORAM_HPP__
|
|
|
|
|
|
+#include <optional>
|
|
|
+
|
|
|
#include "types.hpp"
|
|
|
#include "mpcio.hpp"
|
|
|
#include "coroutine.hpp"
|
|
@@ -22,10 +24,8 @@
|
|
|
// on a Shape shared with other threads or coroutines.
|
|
|
|
|
|
// This is templated, because you can have a Duoram of additively shared
|
|
|
-// (RegAS) or XOR shared (RegXS) elements, or std::arrays of those to
|
|
|
-// get "wide" memory cells.
|
|
|
-
|
|
|
-// The initial implementation is focused on additive shares.
|
|
|
+// (RegAS) or XOR shared (RegXS) elements, or more complex cell types
|
|
|
+// (see cell.hpp for example).
|
|
|
|
|
|
template <typename T>
|
|
|
class Duoram {
|
|
@@ -61,6 +61,10 @@ public:
|
|
|
class Pad;
|
|
|
class Stride;
|
|
|
|
|
|
+ // Oblivious indices for use in related-index ORAM accesses
|
|
|
+ template <typename U, nbits_t WIDTH>
|
|
|
+ class OblivIndex;
|
|
|
+
|
|
|
// Pass the player number and desired size
|
|
|
Duoram(int player, size_t size);
|
|
|
|
|
@@ -88,6 +92,9 @@ class Duoram<T>::Shape {
|
|
|
friend class Pad;
|
|
|
friend class Stride;
|
|
|
|
|
|
+ template <typename U, nbits_t WIDTH>
|
|
|
+ friend class OblivIndex;
|
|
|
+
|
|
|
// When you index into a shape (A[x]), you get one of these types,
|
|
|
// depending on the type of x (the index), _not_ on the type T (the
|
|
|
// underlying type of the Duoram). That is, you can have an
|
|
@@ -361,6 +368,49 @@ public:
|
|
|
RegAS obliv_binary_search(RegAS &target);
|
|
|
};
|
|
|
|
|
|
+// Oblivious indices for use in related-index ORAM accesses.
|
|
|
+
|
|
|
+template <typename T>
|
|
|
+template <typename U, nbits_t WIDTH>
|
|
|
+class Duoram<T>::OblivIndex {
|
|
|
+ template <typename Ux,typename FT,typename FST,typename Sh,nbits_t WIDTHx>
|
|
|
+ friend class Shape::MemRefS;
|
|
|
+
|
|
|
+ int player;
|
|
|
+ std::optional<RDPFTriple<WIDTH>> dt;
|
|
|
+ std::optional<RDPFPair<WIDTH>> dp;
|
|
|
+ nbits_t curdepth, maxdepth;
|
|
|
+ nbits_t next_windex;
|
|
|
+ bool incremental;
|
|
|
+ U idx;
|
|
|
+
|
|
|
+public:
|
|
|
+ // Non-incremental constructor
|
|
|
+ OblivIndex(MPCTIO &tio, yield_t &yield, const U &idx, nbits_t depth) :
|
|
|
+ player(tio.player()), curdepth(depth), maxdepth(depth),
|
|
|
+ next_windex(0), incremental(false), idx(idx)
|
|
|
+ {
|
|
|
+ if (player < 2) {
|
|
|
+ dt = tio.rdpftriple(yield, depth);
|
|
|
+ } else {
|
|
|
+ dp = tio.rdpfpair(yield, depth);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Incremental constructor: only for U=RegXS
|
|
|
+ OblivIndex(MPCTIO &tio, yield_t &yield, nbits_t depth) :
|
|
|
+ player(tio.player()), curdepth(0), maxdepth(depth),
|
|
|
+ next_windex(0), incremental(true), idx(RegXS())
|
|
|
+ {
|
|
|
+ if (player < 2) {
|
|
|
+ dt = tio.rdpftriple(yield, depth, true);
|
|
|
+ } else {
|
|
|
+ dp = tio.rdpfpair(yield, depth, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
// An additive or XOR shared memory reference. You get one of these
|
|
|
// from a Shape A and an additively shared RegAS index x, or an XOR
|
|
|
// shared RegXS index x, with A[x]. Then you perform operations on this
|
|
@@ -378,7 +428,16 @@ template <typename T>
|
|
|
template <typename U, typename FT, typename FST, typename Sh, nbits_t WIDTH>
|
|
|
class Duoram<T>::Shape::MemRefS {
|
|
|
Sh &shape;
|
|
|
- U idx;
|
|
|
+ // oblividx is a reference to the OblivIndex we're using. In the
|
|
|
+ // common case, we own the actual OblivIndex, and it's stored in
|
|
|
+ // our_oblividx, and oblividx is a pointer to that. Sometimes
|
|
|
+ // (for example incremental ORAM accesses), the caller will own (and
|
|
|
+ // modify between uses) the OblivIndex. In that case, oblividx will
|
|
|
+ // be a pointer to the caller's OblivIndex object, and
|
|
|
+ // our_oblividx will be nullopt.
|
|
|
+ std::optional<Duoram<T>::OblivIndex<U,WIDTH>> our_oblividx;
|
|
|
+ Duoram<T>::OblivIndex<U,WIDTH> *oblividx;
|
|
|
+
|
|
|
FST fieldsel;
|
|
|
|
|
|
private:
|
|
@@ -391,12 +450,17 @@ private:
|
|
|
|
|
|
public:
|
|
|
MemRefS<U,FT,FST,Sh,WIDTH>(Sh &shape, const U &idx, FST fieldsel) :
|
|
|
- shape(shape), idx(idx), fieldsel(fieldsel) {}
|
|
|
+ shape(shape), fieldsel(fieldsel) {
|
|
|
+ our_oblividx.emplace(shape.tio, shape.yield, idx,
|
|
|
+ shape.addr_size);
|
|
|
+ oblividx = &(*our_oblividx);
|
|
|
+ }
|
|
|
|
|
|
// Create a MemRefExpl for accessing a partcular field of T
|
|
|
template <typename SFT>
|
|
|
MemRefS<U,SFT,SFT T::*,Sh,WIDTH> field(SFT T::*subfieldsel) {
|
|
|
- auto res = MemRefS<U,SFT,SFT T::*,Sh,WIDTH>(this->shape, idx, subfieldsel);
|
|
|
+ auto res = MemRefS<U,SFT,SFT T::*,Sh,WIDTH>(this->shape,
|
|
|
+ oblividx->idx, subfieldsel);
|
|
|
return res;
|
|
|
}
|
|
|
|