// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package conn

import (
	"crypto/sha256"
	"sync"

	"v.io/v23/context"
	"v.io/v23/security"
	"v.io/v23/vom"
	"v.io/x/ref/lib/security/bcrypter"
)

var encryptionCache = encCache{m: make(map[encCacheKey]bcrypter.WireCiphertext)}

// Maximum no of elements in the cache is 64. This makes the size of
// the cache = (160 + 16 + 32)*64 + (total size of the 64 plaintexts).
// Assume that the average plaintext size is upperbounded by 1KB,
// the size of the cache is upperbound by 77KB.
const encCacheMaxSize = 1 << 6

type encCacheKey struct {
	pattern       security.BlessingPattern
	plaintextHash [sha256.Size]byte
}

type encCache struct {
	sync.RWMutex
	m map[encCacheKey]bcrypter.WireCiphertext
}

func (c *encCache) evictIfNeededLocked() {
	// Randomly evict an entry. Fortunately, map iteration is in random key order
	// (see "Iteration Order" in http://blog.golang.org/go-maps-in-action)
	toEvict := len(c.m) - encCacheMaxSize
	if toEvict <= 0 {
		return
	}
	n := 0
	for key, _ := range c.m {
		delete(c.m, key)
		n++
		if n >= toEvict {
			break
		}
	}
}

func (c *encCache) cache(pattern security.BlessingPattern, plaintext []byte, ctxt bcrypter.WireCiphertext) {
	key := encCacheKey{pattern: pattern, plaintextHash: sha256.Sum256(plaintext)}
	c.Lock()
	defer c.Unlock()
	c.m[key] = ctxt
	c.evictIfNeededLocked()
}

func (c *encCache) ciphertext(pattern security.BlessingPattern, plaintext []byte) (bcrypter.WireCiphertext, bool) {
	key := encCacheKey{pattern: pattern, plaintextHash: sha256.Sum256(plaintext)}
	c.RLock()
	defer c.RUnlock()
	ctxt, b := c.m[key]
	return ctxt, b
}

func encrypt(ctx *context.T, patterns []security.BlessingPattern, v interface{}) ([]bcrypter.WireCiphertext, error) {
	crypter := bcrypter.GetCrypter(ctx)
	if crypter == nil {
		return nil, NewErrNoCrypter(ctx)
	}
	b, err := vom.Encode(v)
	if err != nil {
		return nil, err
	}
	ciphertexts := make([]bcrypter.WireCiphertext, len(patterns))
	for i, p := range patterns {
		if ctxt, exists := encryptionCache.ciphertext(p, b); exists {
			ciphertexts[i] = ctxt
			continue
		}
		ctxt, err := crypter.Encrypt(ctx, p, b)
		if err != nil {
			return nil, err
		}
		ctxt.ToWire(&ciphertexts[i])
		encryptionCache.cache(p, b, ciphertexts[i])
	}
	return ciphertexts, nil
}

func decrypt(ctx *context.T, ciphertexts []bcrypter.WireCiphertext, v interface{}) error {
	crypter := bcrypter.GetCrypter(ctx)
	if crypter == nil {
		return NewErrNoCrypter(ctx)
	}
	var ctxt bcrypter.Ciphertext

	for _, c := range ciphertexts {
		ctxt.FromWire(c)
		if data, err := crypter.Decrypt(ctx, &ctxt); err != nil {
			continue
		} else if err := vom.Decode(data, v); err != nil {
			// Since we use a CCA-2 secure IBE scheme, the ciphertext
			// is not malleable. Therefore if decryption succeeds it
			// ought to be that this crypter has the appropriate private
			// key. Any errors in vom decoding the decrypted plaintext
			// are system errors and must be returned.
			return err
		} else {
			return nil
		}
	}
	return NewErrNoPrivateKey(ctx)
}
