I am trying to implement something similar to the Diffie-Hellman encryption algorithm on elliptic curves, my curve has parameters a = 0, b = 7, p = 115792089237316195423570985008687907853269984665640564039457584007908834671663.
my code consists of three files:
package operations
import (
"Signature/hash"
"Signature/structs"
"crypto/rand"
"fmt"
"github.com/tyler-smith/go-bip39"
"log"
"math/big"
)
func CreatePoint(x, y *big.Int) (*structs.Point, error) {
config := DefaultConfig()
ySquaredModP := new(big.Int).Mod(new(big.Int).Exp(y, big.NewInt(2), &config.P), &config.P)
// (x^3 + a*x + b) % p
rightSide := new(big.Int).Mod(new(big.Int).Add(
new(big.Int).Exp(x, big.NewInt(3), &config.P),
new(big.Int).Add(new(big.Int).Mul(&config.A, x), &config.B),
), &config.P)
if ySquaredModP.Cmp(rightSide) != 0 {
return nil, fmt.Errorf("The point is not on the curve")
}
return &structs.Point{
X: x,
Y: y,
}, nil
}
func DefaultConfig() *structs.Config {
numberString := "115792089237316195423570985008687907853269984665640564039457584007908834671663"
bigNumber := new(big.Int)
bigNumber.SetString(numberString, 10)
return &structs.Config{
A: *big.NewInt(0),
B: *big.NewInt(7),
P: *bigNumber,
}
}
func CreateSignature(part1, part2 *big.Int) *structs.Signature {
return &structs.Signature{
R: part1,
S: part2,
}
}
func CreateMnemonic() string { //Dech-Wallet закинуть туда
entropy, err := bip39.NewEntropy(128)
if err != nil {
log.Panicf("Error %s", err)
}
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
log.Panicf("Error %s", err)
}
return mnemonic
}
func IsEqualTo(point1, point2 structs.Point) bool {
return point1.X.Cmp(point2.X) == 0 && point1.Y.Cmp(point2.Y) == 0
}
func FindInverse(number, modulus *big.Int) *big.Int {
inverse := new(big.Int).ModInverse(number, modulus)
return inverse
}
func DoublePoint(point *structs.Point) *structs.Point {
config := DefaultConfig()
// s = (3 * x^2 + A) / (2 * y)
numerator := new(big.Int).Mul(big.NewInt(3), new(big.Int).Exp(point.X, big.NewInt(2), &config.P))
numerator.Add(numerator, &config.A)
denominator := new(big.Int).Mul(big.NewInt(2), point.Y)
inverse := FindInverse(denominator, &config.P)
slope := new(big.Int).Mul(numerator, inverse)
slope.Mod(slope, &config.P)
// x' = s^2 - 2 * x
xPrime := new(big.Int).Exp(slope, big.NewInt(2), &config.P)
xPrime.Sub(xPrime, new(big.Int).Mul(big.NewInt(2), point.X))
xPrime.Mod(xPrime, &config.P)
// y' = s * (x - x') - y
yPrime := new(big.Int).Mul(slope, new(big.Int).Sub(point.X, xPrime))
yPrime.Sub(yPrime, point.Y)
yPrime.Mod(yPrime, &config.P)
return &structs.Point{X: xPrime, Y: yPrime}
}
func Add(point1, point2 *structs.Point) *structs.Point {
config := DefaultConfig()
if IsEqualTo(*point1, *point2) {
return DoublePoint(point1)
}
deltaX := new(big.Int).Sub(point2.X, point1.X)
deltaY := new(big.Int).Sub(point2.Y, point1.Y)
inverse := FindInverse(deltaX, &config.P)
slope := new(big.Int).Mul(deltaY, inverse)
slope.Mod(slope, &config.P)
x := new(big.Int).Exp(slope, big.NewInt(2), &config.P)
x.Sub(x, point2.X)
x.Sub(x, point1.X)
x.Mod(x, &config.P)
y := new(big.Int).Mul(slope, new(big.Int).Sub(point1.X, x))
y.Sub(y, point1.Y)
y.Mod(y, &config.P)
return &structs.Point{X: x, Y: y}
}
func Multiply(point *structs.Point, times *big.Int) *structs.Point {
result, _ := CreateGPoint()
binTimes := fmt.Sprintf("%b", times)
for i := 1; i < len(binTimes); i++ {
result = DoublePoint(result)
if binTimes[i] == '1' {
result = Add(point, result)
}
}
return result
}
func CreateGPoint() (*structs.Point, error) {
x1 := "55066263022277343669578718895168534326250603453777594175500187360389116729240"
x, successX := new(big.Int).SetString(x1, 10)
if !successX {
panic("Error setting x value")
}
y1 := "32670510020758816978083085130507043184471273380659243275938904335757337482424"
y, successY := new(big.Int).SetString(y1, 10)
if !successY {
panic("Error setting y value")
}
return &structs.Point{
X: x,
Y: y,
}, nil
}
func GenerateRandomNumber() (*big.Int, error) {
n1 := "115792089237316195423570985008687907852837564279074904382605163141518161494337" //115792089237316195423570985008687907852837564279074904382605163141518161494337 value from GP
n, successN := new(big.Int).SetString(n1, 10)
n.Sub(n, big.NewInt(1))
if !successN {
panic("Error setting y value")
}
random, err := rand.Int(rand.Reader, n)
if err != nil {
return nil, err
}
return random, nil
}
package structs
import "math/big"
type Config struct {
A big.Int
B big.Int
P big.Int
}
type Point struct {
X *big.Int
Y *big.Int
}
type Signature struct {
R *big.Int
S *big.Int
}
package main
import (
"Signature/operations"
"fmt"
)
func main() {
// Elliptic Curve Setup
gPoint, err := operations.CreateGPoint()
if err != nil {
fmt.Printf("Error creating GPoint: %s\n", err)
return
}
// Common Parameters
dConfig := operations.DefaultConfig()
// Key Generation
alicePrivateKey, err := operations.GenerateRandomNumber()
if err != nil {
fmt.Printf("Error generating random number for Alice: %s\n", err)
return
}
alicePublicKey := operations.Multiply(gPoint, alicePrivateKey)
bobPrivateKey, err := operations.GenerateRandomNumber()
if err != nil {
fmt.Printf("Error generating random number for Bob: %s\n", err)
return
}
bobPublicKey := operations.Multiply(gPoint, bobPrivateKey)
// Shared Secret Calculation
sharedSecretAlice := operations.Multiply(bobPublicKey, alicePrivateKey)
fmt.Println("Alice X: ", sharedSecretAlice.X)
sharedSecretAlice.X.Mod(sharedSecretAlice.X, &dConfig.P)
fmt.Println("Alice X after modulo: ", sharedSecretAlice.X)
sharedSecretBob := operations.Multiply(alicePublicKey, bobPrivateKey)
fmt.Println("Bob X: ", sharedSecretBob.X)
sharedSecretBob.X.Mod(sharedSecretBob.X, &dConfig.P)
fmt.Println("Bob X after modulo: \n", sharedSecretBob.X)
// Print Results
fmt.Println("Shared Secret (Alice):", sharedSecretAlice.X)
fmt.Println("Shared Secret (Bob):", sharedSecretBob.X)
}
in the output I get values that are the same before and after MOD
How do I get a shared secret for two pairs of keys?
Checked the multiplication and point addition functions, they are correct