// Copyright (c) 2019 The Go 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 edwards25519

import (
	"bytes"
	"encoding/hex"
	"math/big"
	mathrand "math/rand"
	"reflect"
	"testing"
	"testing/quick"
)

// quickCheckConfig returns a quick.Config that scales the max count by the
// given factor if the -short flag is not set.
func quickCheckConfig(slowScale int) *quick.Config {
	cfg := new(quick.Config)
	if !testing.Short() {
		cfg.MaxCountScale = float64(slowScale)
	}
	return cfg
}

var scOneBytes = [32]byte{1}
var scOne, _ = new(Scalar).SetCanonicalBytes(scOneBytes[:])
var scMinusOne, _ = new(Scalar).SetCanonicalBytes(scalarMinusOneBytes[:])

// Generate returns a valid (reduced modulo l) Scalar with a distribution
// weighted towards high, low, and edge values.
func (Scalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
	var s [32]byte
	diceRoll := rand.Intn(100)
	switch {
	case diceRoll == 0:
	case diceRoll == 1:
		s = scOneBytes
	case diceRoll == 2:
		s = scalarMinusOneBytes
	case diceRoll < 5:
		// Generate a low scalar in [0, 2^125).
		rand.Read(s[:16])
		s[15] &= (1 << 5) - 1
	case diceRoll < 10:
		// Generate a high scalar in [2^252, 2^252 + 2^124).
		s[31] = 1 << 4
		rand.Read(s[:16])
		s[15] &= (1 << 4) - 1
	default:
		// Generate a valid scalar in [0, l) by returning [0, 2^252) which has a
		// negligibly different distribution (the former has a 2^-127.6 chance
		// of being out of the latter range).
		rand.Read(s[:])
		s[31] &= (1 << 4) - 1
	}

	val := Scalar{}
	fiatScalarFromBytes((*[4]uint64)(&val.s), &s)
	fiatScalarToMontgomery(&val.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&val.s))

	return reflect.ValueOf(val)
}

func TestScalarGenerate(t *testing.T) {
	f := func(sc Scalar) bool {
		return isReduced(sc.Bytes())
	}
	if err := quick.Check(f, quickCheckConfig(1024)); err != nil {
		t.Errorf("generated unreduced scalar: %v", err)
	}
}

func TestScalarSetCanonicalBytes(t *testing.T) {
	f1 := func(in [32]byte, sc Scalar) bool {
		// Mask out top 4 bits to guarantee value falls in [0, l).
		in[len(in)-1] &= (1 << 4) - 1
		if _, err := sc.SetCanonicalBytes(in[:]); err != nil {
			return false
		}
		repr := sc.Bytes()
		return bytes.Equal(in[:], repr) && isReduced(repr)
	}
	if err := quick.Check(f1, quickCheckConfig(1024)); err != nil {
		t.Errorf("failed bytes->scalar->bytes round-trip: %v", err)
	}

	f2 := func(sc1, sc2 Scalar) bool {
		if _, err := sc2.SetCanonicalBytes(sc1.Bytes()); err != nil {
			return false
		}
		return sc1 == sc2
	}
	if err := quick.Check(f2, quickCheckConfig(1024)); err != nil {
		t.Errorf("failed scalar->bytes->scalar round-trip: %v", err)
	}

	b := scalarMinusOneBytes
	b[31] += 1
	s := scOne
	if out, err := s.SetCanonicalBytes(b[:]); err == nil {
		t.Errorf("SetCanonicalBytes worked on a non-canonical value")
	} else if s != scOne {
		t.Errorf("SetCanonicalBytes modified its receiver")
	} else if out != nil {
		t.Errorf("SetCanonicalBytes did not return nil with an error")
	}
}

func TestScalarSetUniformBytes(t *testing.T) {
	mod, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
	mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
	f := func(in [64]byte, sc Scalar) bool {
		sc.SetUniformBytes(in[:])
		repr := sc.Bytes()
		if !isReduced(repr) {
			return false
		}
		scBig := bigIntFromLittleEndianBytes(repr[:])
		inBig := bigIntFromLittleEndianBytes(in[:])
		return inBig.Mod(inBig, mod).Cmp(scBig) == 0
	}
	if err := quick.Check(f, quickCheckConfig(1024)); err != nil {
		t.Error(err)
	}
}

func TestScalarSetBytesWithClamping(t *testing.T) {
	// Generated with libsodium.js 1.0.18 crypto_scalarmult_ed25519_base.

	random := "633d368491364dc9cd4c1bf891b1d59460face1644813240a313e61f2c88216e"
	s, _ := new(Scalar).SetBytesWithClamping(decodeHex(random))
	p := new(Point).ScalarBaseMult(s)
	want := "1d87a9026fd0126a5736fe1628c95dd419172b5b618457e041c9c861b2494a94"
	if got := hex.EncodeToString(p.Bytes()); got != want {
		t.Errorf("random: got %q, want %q", got, want)
	}

	zero := "0000000000000000000000000000000000000000000000000000000000000000"
	s, _ = new(Scalar).SetBytesWithClamping(decodeHex(zero))
	p = new(Point).ScalarBaseMult(s)
	want = "693e47972caf527c7883ad1b39822f026f47db2ab0e1919955b8993aa04411d1"
	if got := hex.EncodeToString(p.Bytes()); got != want {
		t.Errorf("zero: got %q, want %q", got, want)
	}

	one := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
	s, _ = new(Scalar).SetBytesWithClamping(decodeHex(one))
	p = new(Point).ScalarBaseMult(s)
	want = "12e9a68b73fd5aacdbcaf3e88c46fea6ebedb1aa84eed1842f07f8edab65e3a7"
	if got := hex.EncodeToString(p.Bytes()); got != want {
		t.Errorf("one: got %q, want %q", got, want)
	}
}

func bigIntFromLittleEndianBytes(b []byte) *big.Int {
	bb := make([]byte, len(b))
	for i := range b {
		bb[i] = b[len(b)-i-1]
	}
	return new(big.Int).SetBytes(bb)
}

func TestScalarMultiplyDistributesOverAdd(t *testing.T) {
	multiplyDistributesOverAdd := func(x, y, z Scalar) bool {
		// Compute t1 = (x+y)*z
		var t1 Scalar
		t1.Add(&x, &y)
		t1.Multiply(&t1, &z)

		// Compute t2 = x*z + y*z
		var t2 Scalar
		var t3 Scalar
		t2.Multiply(&x, &z)
		t3.Multiply(&y, &z)
		t2.Add(&t2, &t3)

		reprT1, reprT2 := t1.Bytes(), t2.Bytes()

		return t1 == t2 && isReduced(reprT1) && isReduced(reprT2)
	}

	if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig(1024)); err != nil {
		t.Error(err)
	}
}

func TestScalarAddLikeSubNeg(t *testing.T) {
	addLikeSubNeg := func(x, y Scalar) bool {
		// Compute t1 = x - y
		var t1 Scalar
		t1.Subtract(&x, &y)

		// Compute t2 = -y + x
		var t2 Scalar
		t2.Negate(&y)
		t2.Add(&t2, &x)

		return t1 == t2 && isReduced(t1.Bytes())
	}

	if err := quick.Check(addLikeSubNeg, quickCheckConfig(1024)); err != nil {
		t.Error(err)
	}
}

func TestScalarNonAdjacentForm(t *testing.T) {
	s, _ := (&Scalar{}).SetCanonicalBytes([]byte{
		0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
		0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
		0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
		0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09,
	})

	expectedNaf := [256]int8{
		0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, -11, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1,
		0, 0, 0, 0, 9, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0,
		-9, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 9, 0,
		0, 0, 0, -15, 0, 0, 0, 0, -7, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, -3, 0,
		0, 0, 0, -11, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, 0, 0, 0, 0, 11, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 1, 0, 0,
		0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 13, 0, 0, 0,
		0, 0, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 7,
		0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
	}

	sNaf := s.nonAdjacentForm(5)

	for i := 0; i < 256; i++ {
		if expectedNaf[i] != sNaf[i] {
			t.Errorf("Wrong digit at position %d, got %d, expected %d", i, sNaf[i], expectedNaf[i])
		}
	}
}

type notZeroScalar Scalar

func (notZeroScalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
	var s Scalar
	var isNonZero uint64
	for isNonZero == 0 {
		s = Scalar{}.Generate(rand, size).Interface().(Scalar)
		fiatScalarNonzero(&isNonZero, (*[4]uint64)(&s.s))
	}
	return reflect.ValueOf(notZeroScalar(s))
}

func TestScalarEqual(t *testing.T) {
	if scOne.Equal(scMinusOne) == 1 {
		t.Errorf("scOne.Equal(&scMinusOne) is true")
	}
	if scMinusOne.Equal(scMinusOne) == 0 {
		t.Errorf("scMinusOne.Equal(&scMinusOne) is false")
	}
}
