//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

package bulletproof

import (
	"github.com/pkg/errors"
	"golang.org/x/crypto/sha3"

	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
)

// generators contains a list of points to be used as generators for bulletproofs.
type generators []curves.Point

// ippGenerators holds generators necessary for an Inner Product Proof
// It includes a single u generator, and a list of generators divided in half to G and H
// See lines 10 on pg 16 of https://eprint.iacr.org/2017/1066.pdf
type ippGenerators struct {
	G generators
	H generators
}

// getGeneratorPoints generates generators using HashToCurve with Shake256(domain) as input
// lenVector is the length of the scalars used for the Inner Product Proof
// getGeneratorPoints will return 2*lenVector + 1 total points, split between a single u generator
// and G and H lists of vectors per the IPP specification
// See lines 10 on pg 16 of https://eprint.iacr.org/2017/1066.pdf
func getGeneratorPoints(lenVector int, domain []byte, curve curves.Curve) (*ippGenerators, error) {
	shake := sha3.NewShake256()
	_, err := shake.Write(domain)
	if err != nil {
		return nil, errors.Wrap(err, "getGeneratorPoints shake.Write")
	}
	numPoints := lenVector * 2
	points := make([]curves.Point, numPoints)
	for i := 0; i < numPoints; i++ {
		bytes := [64]byte{}
		_, err := shake.Read(bytes[:])
		if err != nil {
			return nil, errors.Wrap(err, "getGeneratorPoints shake.Read")
		}
		nextPoint := curve.Point.Hash(bytes[:])
		points[i] = nextPoint
	}
	// Get G and H by splitting points in half
	G, H, err := splitPointVector(points)
	if err != nil {
		return nil, errors.Wrap(err, "getGeneratorPoints splitPointVector")
	}
	out := ippGenerators{G: G, H: H}

	return &out, nil
}