func main() {
	p := big.NewInt(0)
	p.SetString(pStr, 16)
	g := big.NewInt(2)

	A, a := util.GenExpPair(p, g)
	B, b := util.GenExpPair(p, g)

	s1 := big.NewInt(0)
	s2 := big.NewInt(0)
	s1.Exp(B, a, p)
	s2.Exp(A, b, p)
	fmt.Printf("a=%s\nA=%s\nb=%s\nB=%s\ns1=%s\ns2=%s \n", a, A, b, B, s1, s2)
}
func main() {
	p := big.NewInt(0)
	p.SetString(pStr, 16)
	g := big.NewInt(2)
	A, a := util.GenExpPair(p, g)
	fmt.Println("A->B: p, g, A")

	// A->M
	// Send "p", "g", "A"

	// M->B
	// Send "p", "g", "p"

	B, b := util.GenExpPair(p, g)
	sB := big.NewInt(0)
	sB.Exp(p, b, p)
	sB.Mod(sB, p)
	fmt.Println("B->M: B")

	// B->M
	// Send "B"

	// M->A
	// Send "p"

	sA := big.NewInt(0)
	sA.Exp(p, a, p)
	sA.Mod(sA, p)

	t1 := []byte("secret message from Alice")
	ct1, iv1 := aesCrypt(sA, t1)
	fmt.Printf("A->M->B ct1=%x iv1=%x\n", ct1, iv1)

	// A->M
	// Send ct1, iv1 == AES-CBC(SHA1(s)[0:16], iv=random(16), msg) + iv

	// decrypt ct from A intercepted by MITM
	t1M := aesDecrypt(big.NewInt(0), ct1, iv1)
	fmt.Println("A-> intercepted:", string(t1M))

	// M->B
	t1B := aesDecrypt(sB, ct1, iv1)
	fmt.Println("B received:", string(t1B))

	t2 := []byte("secret message from Bob")
	ct2, iv2 := aesCrypt(sB, t2)
	fmt.Printf("B->M->A ct2=%x iv2=%x\n", ct2, iv2)

	// B->A
	// Send AES-CBC(SHA1(s)[0:16], iv=random(16), A's msg) + iv

	// decrypt ct from A intercepted by MITM
	t2M := aesDecrypt(big.NewInt(0), ct2, iv2)
	fmt.Println("B-> intercepted:", string(t2M))

	t2A := aesDecrypt(sA, ct2, iv2)
	fmt.Println("A received:", string(t2A))

	fmt.Printf(" a = %x\n A = %x\n b = %x\n B = %x\n sA == sB -> %t \n", a, A, b, B, sA.Cmp(sB) == 0)
	fmt.Printf(" sA = %x \n sB = %x\n", sA, sB)

	// golang 1.5 big with math/big.Exp(x, y, m)
	// for x>=m and y ~= x it returns m instead of 0
	//
	// {
	//	a, _ := big.NewInt(01).SetString(pStr, 16)
	//	b := util.RandomBig(p.Div(p, big.NewInt(1000000)))
	//	c, _ := big.NewInt(0).SetString(pStr, 16)
	//	z := big.NewInt(01)
	//	z.Exp(a, b, c)
	//	z.Mod(z, c)
	//	zero := big.NewInt(0)
	//	fmt.Printf("z=%x %d\n", z, zero.Cmp(z))
	// }
}
func main() {
	// C & S
	N, _ := big.NewInt(0).SetString(NStr, 0)
	g := big.NewInt(2)
	k := big.NewInt(3)
	// i := []byte("*****@*****.**")
	p := []byte("secret-pass")

	// S
	salt := util.RandBytes(16)
	xH := sha256.Sum256(append(salt, p...))
	x := big.NewInt(0).SetBytes(xH[0:32])
	fmt.Printf("%s \n%x\n\n", x, x)
	v := big.NewInt(0).Exp(g, x, N)
	v.Mod(v, N)
	fmt.Printf("v = %x\n", v)

	// C->S: I, A=g**a % N
	A, a := util.GenExpPair(N, g)

	// S->C: salt, B=kv + g**b % N
	b := util.RandomBig(N)
	B := big.NewInt(0).Exp(g, b, N)
	kv := big.NewInt(0).Mul(k, v)
	B.Add(kv, B)
	B.Mod(B, N)

	// S, C
	uH := sha256.Sum256([]byte(A.String() + B.String()))
	u := big.NewInt(0).SetBytes(uH[0:32])

	// C
	xHClient := sha256.Sum256(append(salt, p...))
	xClient := big.NewInt(0).SetBytes(xHClient[0:32])
	// S = (B - k * g**x)**(a + u * x) % N
	left := big.NewInt(0)
	left.Exp(g, xClient, N)
	left.Mul(k, left)
	left.Sub(B, left)
	right := big.NewInt(0)
	right.Mul(u, xClient)
	right.Add(a, right)
	sClient := big.NewInt(0).Exp(left, right, N)
	sClient.Mod(sClient, N) // S
	KClient := sha256.Sum256(sClient.Bytes())
	fmt.Printf("KClient = %x\n", KClient)

	HMacClient := util.HMacSha256(KClient[:32], salt)
	fmt.Printf("HMAC Client = %x\n", HMacClient)

	// S
	// sServer = (A * v**u) ** b % N
	left.Exp(v, u, N)
	left.Mul(A, left)
	sServer := big.NewInt(0).Exp(left, b, N)
	KServer := sha256.Sum256(sServer.Bytes())
	fmt.Printf("KServer = %x\n", KServer)

	HMacServer := util.HMacSha256(KServer[:32], salt)
	fmt.Printf("HMAC Server = %x\n", HMacServer)
}