diff --git a/dppk.go b/dppk.go index 82220f0..4322415 100644 --- a/dppk.go +++ b/dppk.go @@ -9,30 +9,31 @@ import ( // PRIME is the prime number used in the DPPK protocol. const PRIME = "32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596231637" -//const PRIME = "997" - -// PrivateKey +// PrivateKey represents a private key in the DPPK protocol. type PrivateKey struct { - s0 *big.Int - a0, a1, b0, b1 *big.Int - s0a0, s0b0 *big.Int // the constant term of the polynomial + s0 *big.Int // Initial secret value + a0, a1, b0, b1 *big.Int // Coefficients for the polynomials + s0a0, s0b0 *big.Int // Precomputed constant terms of the polynomials PublicKey } +// PublicKey represents a public key in the DPPK protocol. type PublicKey struct { - prime *big.Int - vecU []*big.Int - vecQ []*big.Int + prime *big.Int // Prime number used in the protocol + vecU []*big.Int // Coefficients for polynomial U + vecQ []*big.Int // Coefficients for polynomial Q } -// NewDPPK creates a new DPPK instance with the given order. +// GenerateKey generates a new DPPK private key with the given order. func GenerateKey(order int) (*PrivateKey, error) { + // Ensure the order is at least 5 if order < 5 { return nil, errors.New("order must be at least 5") } prime, _ := big.NewInt(0).SetString(PRIME, 10) RETRY: + // Generate random coefficients for the polynomials a0, err := rand.Int(rand.Reader, prime) if err != nil { return nil, err @@ -53,13 +54,12 @@ RETRY: return nil, err } - // make sure they're different + // Ensure all coefficients are distinct if a0.Cmp(a1) == 0 || a0.Cmp(b0) == 0 || a0.Cmp(b1) == 0 || a1.Cmp(b0) == 0 || a1.Cmp(b1) == 0 || b0.Cmp(b1) == 0 { goto RETRY } - // Bn(X) - // coefficients s^0 --> s^N + // Generate random coefficients for the polynomial Bn(x) Bn := make([]*big.Int, order) for i := 0; i < len(Bn); i++ { r, err := rand.Int(rand.Reader, prime) @@ -68,10 +68,10 @@ RETRY: } Bn[i] = r } - // the coefficient of x^n is 1 + // Ensure the coefficient of x^n is 1 Bn = append(Bn, big.NewInt(1)) - // compute coefficients of vector U and V + // Initialize vectors for polynomials U(x) and Q(x) vecU := make([]*big.Int, order+3) vecV := make([]*big.Int, order+3) for i := 0; i < order+3; i++ { @@ -81,9 +81,9 @@ RETRY: bigInt := new(big.Int) - // x^2 + a1x + a0 + // Compute the coefficients for the polynomials U(x) and Q(x) using Vieta's formulas for i := 0; i < order+1; i++ { - // vector P + // Vector U vecU[i].Add(vecU[i], bigInt.Mul(a0, Bn[i])) vecU[i].Mod(vecU[i], prime) @@ -93,7 +93,7 @@ RETRY: vecU[i+2].Add(vecU[i+2], Bn[i]) vecU[i+2].Mod(vecU[i+2], prime) - // vector Q + // Vector Q vecV[i].Add(vecV[i], bigInt.Mul(b0, Bn[i])) vecV[i].Mod(vecV[i], prime) @@ -104,7 +104,7 @@ RETRY: vecV[i+2].Mod(vecV[i+2], prime) } - //fmt.Println(vecP[0], bigInt.Mod(bigInt.Mul(a0, coeff_base[0]), prime)) + // Create the private key priv := &PrivateKey{ s0: Bn[0], a0: a0, @@ -115,18 +115,22 @@ RETRY: s0b0: vecV[0], } - // remove v0 and v(N+2) + // Set the public key vectors, excluding the first and last elements priv.PublicKey.vecU = vecU[1 : order+2] priv.PublicKey.vecQ = vecV[1 : order+2] priv.PublicKey.prime = prime return priv, nil } +// Encrypt encrypts a message using the given public key. func (dppk *PrivateKey) Encrypt(pk *PublicKey, msg []byte) (Ps *big.Int, Qs *big.Int, err error) { + // Convert the message to a big integer secret := new(big.Int).SetBytes(msg) if secret.Cmp(dppk.PublicKey.prime) >= 0 { return nil, nil, errors.New("data is too large") } + + // Extend the vectors U and Q with a constant term of 1 vecUExt := make([]*big.Int, len(dppk.PublicKey.vecU)+1) vecQExt := make([]*big.Int, len(dppk.PublicKey.vecQ)+1) copy(vecUExt, pk.vecU) @@ -134,12 +138,14 @@ func (dppk *PrivateKey) Encrypt(pk *PublicKey, msg []byte) (Ps *big.Int, Qs *big vecUExt[len(vecUExt)-1] = big.NewInt(1) vecQExt[len(vecQExt)-1] = big.NewInt(1) + // Initialize variables for the encryption process Ps = big.NewInt(0) Qs = big.NewInt(0) Si := new(big.Int).Set(secret) UiSi := new(big.Int) ViSi := new(big.Int) + // Compute the encrypted values Ps and Qs for i := range vecUExt { UiSi.Mul(Si, vecUExt[i]) UiSi.Mod(UiSi, pk.prime) @@ -158,7 +164,9 @@ func (dppk *PrivateKey) Encrypt(pk *PublicKey, msg []byte) (Ps *big.Int, Qs *big return Ps, Qs, nil } +// Decrypt decrypts the encrypted values Ps and Qs using the private key. func (dppk *PrivateKey) Decrypt(Ps *big.Int, Qs *big.Int) (x1, x2 *big.Int, err error) { + // Adjust Ps and Qs with precomputed constant terms _Ps := new(big.Int).Set(Ps) _Qs := new(big.Int).Set(Qs) _Ps.Add(_Ps, dppk.s0a0) @@ -167,22 +175,22 @@ func (dppk *PrivateKey) Decrypt(Ps *big.Int, Qs *big.Int) (x1, x2 *big.Int, err _Qs.Mod(_Qs, dppk.PublicKey.prime) // As: - // Ps := Bn * (x^2 + a1x + a0) mod p - // Qs := Bn * (x^2 + b1x + b0) mod p + // Ps := Bn * (x^2 + a1x + a0) mod p + // Qs := Bn * (x^2 + b1x + b0) mod p // // We have: - // Ps*revBn(s):= (x^2 + a1x + a0) mod p - // Qs*revBn(s):= (x^2 + b1x + b0) mod p + // Ps*revBn(s):= (x^2 + a1x + a0) mod p + // Qs*revBn(s):= (x^2 + b1x + b0) mod p // // Then: - // Ps* Qs * revBn(s):= (x^2 + a1x + a0) * Qs mod p - // Ps* Qs * revBn(s):= (x^2 + b1x + b0) * Ps mod p + // Ps* Qs * revBn(s):= (x^2 + a1x + a0) * Qs mod p + // Ps* Qs * revBn(s):= (x^2 + b1x + b0) * Ps mod p // // Solve this equation to get x - // (x^2 + a1x + a0) * Qs == (x^2 + b1x + b0) * Ps modp - + // (x^2 + a1x + a0) * Qs == (x^2 + b1x + b0) * Ps modp // the following procedure will be formalized to : // ax^2 + bx + c = 0 + a := new(big.Int) revPs := new(big.Int).Sub(dppk.PublicKey.prime, _Ps) a.Add(_Qs, revPs) @@ -204,6 +212,8 @@ func (dppk *PrivateKey) Decrypt(Ps *big.Int, Qs *big.Int) (x1, x2 *big.Int, err c.Add(a0Qs, revb0Ps) c.Mod(c, dppk.PublicKey.prime) + // Solve the quadratic equation derived from Ps and Qs + // Compute the discriminant of the quadratic equation bsquared := new(big.Int).Mul(b, b) bsquared.Mod(bsquared, dppk.PublicKey.prime) @@ -214,10 +224,10 @@ func (dppk *PrivateKey) Decrypt(Ps *big.Int, Qs *big.Int) (x1, x2 *big.Int, err squared := big.NewInt(0).Add(bsquared, invFourac) squared.Mod(squared, dppk.PublicKey.prime) - // solve quadratic equation + // Solve the quadratic equation root := new(big.Int).ModSqrt(squared, dppk.PublicKey.prime) - // div 2a + // Calculate the roots of the equation inv2a := big.NewInt(2) inv2a.Mul(inv2a, a) inv2a.Mod(inv2a, dppk.PublicKey.prime)