You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
1.5 KiB
61 lines
1.5 KiB
package crypto |
|
|
|
import ( |
|
"math/big" |
|
|
|
"github.com/go-faster/errors" |
|
) |
|
|
|
// CheckGP checks whether g generates a cyclic subgroup of prime order (p-1)/2, i.e. is a quadratic residue mod p. |
|
// Also check that g is 2, 3, 4, 5, 6 or 7. |
|
// |
|
// This function is needed by some Telegram algorithms(Key generation, SRP 2FA). |
|
// |
|
// See https://core.telegram.org/mtproto/auth_key. |
|
// |
|
// See https://core.telegram.org/api/srp. |
|
func CheckGP(g int, p *big.Int) error { |
|
// Since g is always equal to 2, 3, 4, 5, 6 or 7, |
|
// this is easily done using quadratic reciprocity law, yielding a simple condition on p mod 4g -- namely, |
|
var result bool |
|
switch g { |
|
case 2: |
|
// p mod 8 = 7 for g = 2; |
|
result = checkSubgroup(p, 8, 7) |
|
case 3: |
|
// p mod 3 = 2 for g = 3; |
|
result = checkSubgroup(p, 3, 2) |
|
case 4: |
|
// no extra condition for g = 4 |
|
result = true |
|
case 5: |
|
// p mod 5 = 1 or 4 for g = 5; |
|
result = checkSubgroup(p, 5, 1, 4) |
|
case 6: |
|
// p mod 24 = 19 or 23 for g = 6; |
|
result = checkSubgroup(p, 24, 19, 23) |
|
case 7: |
|
// and p mod 7 = 3, 5 or 6 for g = 7. |
|
result = checkSubgroup(p, 7, 3, 5, 6) |
|
default: |
|
return errors.Errorf("unexpected g = %d: g should be equal to 2, 3, 4, 5, 6 or 7", g) |
|
} |
|
|
|
if !result { |
|
return errors.New("g should be a quadratic residue mod p") |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func checkSubgroup(p *big.Int, divider int64, expected ...int64) bool { |
|
rem := new(big.Int).Rem(p, big.NewInt(divider)).Int64() |
|
|
|
for _, e := range expected { |
|
if rem == e { |
|
return true |
|
} |
|
} |
|
|
|
return false |
|
}
|
|
|