func (c *Client) get_path(n int) ([]int, error) {
    if n < 0 || n >= c.N {
        return nil, errors.New("Block number out of range")
    }
    path := make([]int, c.L+1)
    cur_n := n
    for i := c.L; i >= 0; i-- {
        path[i] = cur_n
        cur_n /= 2
    }
    return path, nil
}
returns the path to block n
package oram
import (
	"crypto/rand"
	"errors"
	"math"
    "fmt"
    "encoding/json"
    "log"
)
type Client struct {
	N          int
	L          int
	B          int
	Z          int
	stash      []Block
	pos        map[int]int
	keys       []byte
    conn       *Conn
}
func InitClient(N int, Z int, B int) *Client {
	c := &Client{N: N, B: B, Z: Z, pos: make(map[int]int)}
	c.L = int(math.Ceil(math.Log2(float64(N))))
	random_leaves := random_perm(1 << uint(c.L))
	for i := 0; i < N; i++ {
		c.pos[i] = int(random_leaves[i])
	}
	return c
}
func (c *Client) AddServer(serverAddr string, N int, Z int) error {
    var err error
    c.conn, err = OpenConnection(serverAddr)
    if err != nil {
        fmt.Println("Server not up")
    }
	key := make([]byte, 16)
	rand.Read(key)
	c.keys = key
	S := c.N * c.L
	c.stash = make([]Block, 0, S)
	err = c.init_server_storage(key)
	return err
}
func (c *Client) RemoveServer() {
    CloseConnection(c.conn)
}
func (c *Client) init_server_storage(key []byte) error {
	for i := 0; i <= c.L; i++ {
		for j := 0; j < (1 << uint(i)); j++ {
			bucket := make_bucket(nil, c.Z, key, c.B)
			c.RemoteWrite(bucket, i, j)
		}
	}
	return nil
}
func (c *Client) Access(write bool, a int, data []byte) ([]byte, error) {
    ret := make([]byte, c.B)
	key := c.keys
	x, prs := c.pos[a]
	if prs == false {
		return ret, errors.New("Tried to look up invalid block number in pos!")
	}
	num_leaves := 1 << uint(c.L)
	new_leaf := gen_int(num_leaves)
	c.pos[a] = new_leaf
	buckets, err := c.get_path_buckets(x)
	if err != nil {
		return ret, err
	}
	cur_stash := c.stash
	nondummy := find_nondummy(buckets, key)
	path_start := len(cur_stash)
	cur_stash = append(cur_stash, nondummy...)
	path_end := len(cur_stash)
	i := slice_find_block(cur_stash, a)
	if write {
		new_blk := data
		if i == -1 {
			cur_stash = append(cur_stash, new_blk)
		} else {
			cur_stash[i] = new_blk
		}
		ret = data
	} else {
		if i != -1 {
			ret = cur_stash[i]
		}
	}
	old_path, err := c.get_path(x)
	if err != nil {
		return ret, err
	}
	new_path, err := c.get_path(new_leaf)
	if err != nil {
		return ret, err
	}
	num_inters := 0
	for i := range old_path {
		if old_path[i] == new_path[i] {
			num_inters += 1
		}
	}
	inters := make([]int, num_inters)
	for i := 0; i < num_inters; i++ {
		inters[i] = old_path[num_inters-1-i]
	}
	blk_to_write := make([]Block, 0, len(inters))
	num := cap(blk_to_write) - len(blk_to_write)
	if path_end - path_start < num  {
		num = path_end - path_start
	}
	blk_to_write = append(blk_to_write, cur_stash[path_start : path_start + num]...)
	if len(blk_to_write) < cap(blk_to_write) {
		num = cap(blk_to_write) - len(blk_to_write)
		if len(cur_stash) < num {
			num = len(cur_stash)
		}
		blk_to_write = append(blk_to_write, cur_stash[:num]...)
		cur_stash = append(cur_stash[num:])
	}
	if len(blk_to_write) < cap(blk_to_write) {
		dummy := make([]Block, len(inters)-len(blk_to_write))
		for i := range dummy {
			dummy[i] = dummy_block(c.B)
		}
		blk_to_write = append(blk_to_write, dummy...)
	}
	for i := range inters {
		cur_l := len(inters) - 1 - i
		bucket := make_bucket([]Block{blk_to_write[i]}, c.Z, key, c.B)
		c.RemoteWrite(bucket, cur_l, inters[i])
	}
	if len(inters) < len(blk_to_write) {
		extra_blks := blk_to_write[len(inters):]
		cur_stash = append(cur_stash, extra_blks...)
	}
	c.stash = cur_stash
	return ret, nil
}