// Retrieve value from AChord and decrypt it.
func (c *Client) achordGet(b *buf) error {
        p := c.bufGet()
        defer c.bufPut(p)

        var n int
        var err error

        // BUG(ls): The decision to backoff and retry should be left to
        // callers. We have no good way to do that yet. We should probably
        // start by threading context values throughout the FS code so we can
        // at least support cancelation. Clients then cancel the contexts to
        // stop the retry loop. Especially important for FUSE as programs
        // accessing the FS end up unkillable if we don't do this.
        for i := 0; i < 10; i++ {
                n, err = c.kv.Get(context.TODO(), b.addr[:], p.data)
                if err == nil {
                        break
                }
                if !netutil.IsTemporary(err) {
                        return err
                }
                backoff(i, err)
        }
        if err != nil {
                return err
        }
        if n < blockOverhead {
                return syscall.EIO
        }
        pp := p.data[:n]

        var nonce [24]byte
        pp = pp[copy(nonce[:], pp):]

        zp, ok := secretbox.Open(nil, pp, &nonce, &c.key)
        if !ok {
                return errAuth
        }

        q := zp
        if b.addr != c.sbp {
                q, err = c.decode(nil, zp)
                if err != nil {
                        return err
                }
        }

        copy(b.data, q)
        b.flags |= bufValid

        return nil
}

// Encrypt buffer and upload it to AChord.
func (c *Client) achordPut(b *buf) error {
        p := c.bufGet()
        defer c.bufPut(p)

        zp := b.data
        if b.addr != c.sbp {
                // never compress or otherwise transform the superblock
                zp = c.encode(nil, b.data)
        }

        var nonce [24]byte
        if _, err := rand.Read(nonce[:]); err != nil {
                return err
        }
        pp := p.data[copy(p.data, nonce[:]):]

        q := secretbox.Seal(pp[:0], zp, &nonce, &c.key)

        var err error
        for i := 0; i < 10; i++ {
                err = c.kv.Put(context.TODO(), b.addr[:], p.data[:len(nonce)+len(q)])
                if err == nil {
                        b.flags &^= bufDirty
                        break
                }
                if !netutil.IsTemporary(err) {
                        return err
                }
                backoff(i, err)
        }

        return err
}