mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-08-04 14:10:54 -04:00
move vendor to external
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
// +build noasm !amd64
|
||||
|
||||
package internal
|
||||
|
||||
// helper used for Uint128 representation
|
||||
type Uint128 struct {
|
||||
H, L uint64
|
||||
}
|
||||
|
||||
// Adds 2 64bit digits in constant time.
|
||||
// Returns result and carry (1 or 0)
|
||||
func Addc64(cin, a, b uint64) (ret, cout uint64) {
|
||||
t := a + cin
|
||||
ret = b + t
|
||||
cout = ((a & b) | ((a | b) & (^ret))) >> 63
|
||||
return
|
||||
}
|
||||
|
||||
// Substracts 2 64bit digits in constant time.
|
||||
// Returns result and borrow (1 or 0)
|
||||
func Subc64(bIn, a, b uint64) (ret, bOut uint64) {
|
||||
var tmp1 = a - b
|
||||
// Set bOut if bIn!=0 and tmp1==0 in constant time
|
||||
bOut = bIn & (1 ^ ((tmp1 | uint64(0-tmp1)) >> 63))
|
||||
// Constant time check if x<y
|
||||
bOut |= (a ^ ((a ^ b) | (uint64(a-b) ^ b))) >> 63
|
||||
ret = tmp1 - bIn
|
||||
return
|
||||
}
|
||||
|
||||
// Multiplies 2 64bit digits in constant time
|
||||
func Mul64(a, b uint64) (res Uint128) {
|
||||
var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64
|
||||
var res1, res2, res3 uint64
|
||||
var carry, maskL, maskH, temp uint64
|
||||
|
||||
maskL = (^maskL) >> 32
|
||||
maskH = ^maskL
|
||||
|
||||
al = a & maskL
|
||||
ah = a >> 32
|
||||
bl = b & maskL
|
||||
bh = b >> 32
|
||||
|
||||
albl = al * bl
|
||||
albh = al * bh
|
||||
ahbl = ah * bl
|
||||
ahbh = ah * bh
|
||||
res.L = albl & maskL
|
||||
|
||||
res1 = albl >> 32
|
||||
res2 = ahbl & maskL
|
||||
res3 = albh & maskL
|
||||
temp = res1 + res2 + res3
|
||||
carry = temp >> 32
|
||||
res.L ^= temp << 32
|
||||
|
||||
res1 = ahbl >> 32
|
||||
res2 = albh >> 32
|
||||
res3 = ahbh & maskL
|
||||
temp = res1 + res2 + res3 + carry
|
||||
res.H = temp & maskL
|
||||
carry = temp & maskH
|
||||
res.H ^= (ahbh & maskH) + carry
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
package internal
|
||||
|
||||
type CurveOperations struct {
|
||||
Params *SidhParams
|
||||
}
|
||||
|
||||
// Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
|
||||
// is returned in jBytes buffer, encoded in little-endian format. Caller
|
||||
// provided jBytes buffer has to be big enough to j-invariant value. In case
|
||||
// of SIDH, buffer size must be at least size of shared secret.
|
||||
// Implementation corresponds to Algorithm 9 from SIKE.
|
||||
func (c *CurveOperations) Jinvariant(cparams *ProjectiveCurveParameters, jBytes []byte) {
|
||||
var j, t0, t1 Fp2Element
|
||||
|
||||
op := c.Params.Op
|
||||
op.Square(&j, &cparams.A) // j = A^2
|
||||
op.Square(&t1, &cparams.C) // t1 = C^2
|
||||
op.Add(&t0, &t1, &t1) // t0 = t1 + t1
|
||||
op.Sub(&t0, &j, &t0) // t0 = j - t0
|
||||
op.Sub(&t0, &t0, &t1) // t0 = t0 - t1
|
||||
op.Sub(&j, &t0, &t1) // t0 = t0 - t1
|
||||
op.Square(&t1, &t1) // t1 = t1^2
|
||||
op.Mul(&j, &j, &t1) // j = j * t1
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Square(&t1, &t0) // t1 = t0^2
|
||||
op.Mul(&t0, &t0, &t1) // t0 = t0 * t1
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Inv(&j, &j) // j = 1/j
|
||||
op.Mul(&j, &t0, &j) // j = t0 * j
|
||||
|
||||
c.Fp2ToBytes(jBytes, &j)
|
||||
}
|
||||
|
||||
// Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
|
||||
// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
|
||||
func (c *CurveOperations) RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2Element) {
|
||||
var t0, t1 Fp2Element
|
||||
|
||||
op := c.Params.Op
|
||||
op.Add(&t1, xp, xq) // t1 = Xp + Xq
|
||||
op.Mul(&t0, xp, xq) // t0 = Xp * Xq
|
||||
op.Mul(&curve.A, xr, &t1) // A = X(q-p) * t1
|
||||
op.Add(&curve.A, &curve.A, &t0) // A = A + t0
|
||||
op.Mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
|
||||
op.Sub(&curve.A, &curve.A, &c.Params.OneFp2) // A = A - 1
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Add(&t1, &t1, xr) // t1 = t1 + X(q-p)
|
||||
op.Add(&t0, &t0, &t0) // t0 = t0 + t0
|
||||
op.Square(&curve.A, &curve.A) // A = A^2
|
||||
op.Inv(&t0, &t0) // t0 = 1/t0
|
||||
op.Mul(&curve.A, &curve.A, &t0) // A = A * t0
|
||||
op.Sub(&curve.A, &curve.A, &t1) // A = A - t1
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : A-2C)
|
||||
func (c *CurveOperations) CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coef CurveCoefficientsEquiv
|
||||
var c2 Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
op.Add(&c2, &cparams.C, &cparams.C)
|
||||
// A24p = A+2*C
|
||||
op.Add(&coef.A, &cparams.A, &c2)
|
||||
// A24m = A-2*C
|
||||
op.Sub(&coef.C, &cparams.A, &c2)
|
||||
return coef
|
||||
}
|
||||
|
||||
// Computes equivalence (A:C) ~ (A+2C : 4C)
|
||||
func (c *CurveOperations) CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
var op = c.Params.Op
|
||||
|
||||
op.Add(&coefEq.C, &cparams.C, &cparams.C)
|
||||
// A24p = A+2C
|
||||
op.Add(&coefEq.A, &cparams.A, &coefEq.C)
|
||||
// C24 = 4*C
|
||||
op.Add(&coefEq.C, &coefEq.C, &coefEq.C)
|
||||
return coefEq
|
||||
}
|
||||
|
||||
// Helper function for RightToLeftLadder(). Returns A+2C / 4.
|
||||
func (c *CurveOperations) CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2Element) {
|
||||
var tmp Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
// 2C
|
||||
op.Add(&tmp, &cparams.C, &cparams.C)
|
||||
// A+2C
|
||||
op.Add(&ret, &cparams.A, &tmp)
|
||||
// 1/4C
|
||||
op.Add(&tmp, &tmp, &tmp)
|
||||
op.Inv(&tmp, &tmp)
|
||||
// A+2C/4C
|
||||
op.Mul(&ret, &ret, &tmp)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
|
||||
func (c *CurveOperations) RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
var op = c.Params.Op
|
||||
|
||||
op.Add(&cparams.A, &coefEq.A, &coefEq.C)
|
||||
// cparams.A = 2*(A+2C+A-2C) = 4A
|
||||
op.Add(&cparams.A, &cparams.A, &cparams.A)
|
||||
// cparams.C = (A+2C-A+2C) = 4C
|
||||
op.Sub(&cparams.C, &coefEq.A, &coefEq.C)
|
||||
return
|
||||
}
|
||||
|
||||
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
|
||||
func (c *CurveOperations) RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
|
||||
var op = c.Params.Op
|
||||
// cparams.C = (4C)*1/2=2C
|
||||
op.Mul(&cparams.C, &coefEq.C, &c.Params.HalfFp2)
|
||||
// cparams.A = A+2C - 2C = A
|
||||
op.Sub(&cparams.A, &coefEq.A, &cparams.C)
|
||||
// cparams.C = 2C * 1/2 = C
|
||||
op.Mul(&cparams.C, &cparams.C, &c.Params.HalfFp2)
|
||||
return
|
||||
}
|
||||
|
||||
// Combined coordinate doubling and differential addition. Takes projective points
|
||||
// P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
|
||||
// Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
|
||||
func (c *CurveOperations) xDblAdd(P, Q, QmP *ProjectivePoint, a24 *Fp2Element) (dblP, PaQ ProjectivePoint) {
|
||||
var t0, t1, t2 Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
xQmP, zQmP := &QmP.X, &QmP.Z
|
||||
xPaQ, zPaQ := &PaQ.X, &PaQ.Z
|
||||
x2P, z2P := &dblP.X, &dblP.Z
|
||||
xP, zP := &P.X, &P.Z
|
||||
xQ, zQ := &Q.X, &Q.Z
|
||||
|
||||
op.Add(&t0, xP, zP) // t0 = Xp+Zp
|
||||
op.Sub(&t1, xP, zP) // t1 = Xp-Zp
|
||||
op.Square(x2P, &t0) // 2P.X = t0^2
|
||||
op.Sub(&t2, xQ, zQ) // t2 = Xq-Zq
|
||||
op.Add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
|
||||
op.Mul(&t0, &t0, &t2) // t0 = t0 * t2
|
||||
op.Mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
|
||||
op.Mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
|
||||
op.Sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
|
||||
op.Mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
|
||||
op.Mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
|
||||
op.Sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
|
||||
op.Add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
|
||||
op.Add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
|
||||
op.Mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
|
||||
op.Square(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
|
||||
op.Square(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
|
||||
op.Mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
|
||||
op.Mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
|
||||
return
|
||||
}
|
||||
|
||||
// Given the curve parameters, xP = x(P), computes xP = x([2^k]P)
|
||||
// Safe to overlap xP, x2P.
|
||||
func (c *CurveOperations) Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1 Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
op.Sub(&t0, x, z) // t0 = Xp - Zp
|
||||
op.Add(&t1, x, z) // t1 = Xp + Zp
|
||||
op.Square(&t0, &t0) // t0 = t0 ^ 2
|
||||
op.Square(&t1, &t1) // t1 = t1 ^ 2
|
||||
op.Mul(z, ¶ms.C, &t0) // Z2p = C24 * t0
|
||||
op.Mul(x, z, &t1) // X2p = Z2p * t1
|
||||
op.Sub(&t1, &t1, &t0) // t1 = t1 - t0
|
||||
op.Mul(&t0, ¶ms.A, &t1) // t0 = A24+ * t1
|
||||
op.Add(z, z, &t0) // Z2p = Z2p + t0
|
||||
op.Mul(z, z, &t1) // Zp = Z2p * t1
|
||||
}
|
||||
}
|
||||
|
||||
// Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P).
|
||||
//
|
||||
// Safe to overlap xP, xR.
|
||||
func (c *CurveOperations) Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
|
||||
var t0, t1, t2, t3, t4, t5, t6 Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
x, z := &xP.X, &xP.Z
|
||||
for i := uint32(0); i < k; i++ {
|
||||
op.Sub(&t0, x, z) // t0 = Xp - Zp
|
||||
op.Square(&t2, &t0) // t2 = t0^2
|
||||
op.Add(&t1, x, z) // t1 = Xp + Zp
|
||||
op.Square(&t3, &t1) // t3 = t1^2
|
||||
op.Add(&t4, &t1, &t0) // t4 = t1 + t0
|
||||
op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
op.Square(&t1, &t4) // t1 = t4^2
|
||||
op.Sub(&t1, &t1, &t3) // t1 = t1 - t3
|
||||
op.Sub(&t1, &t1, &t2) // t1 = t1 - t2
|
||||
op.Mul(&t5, &t3, ¶ms.A) // t5 = t3 * A24+
|
||||
op.Mul(&t3, &t3, &t5) // t3 = t5 * t3
|
||||
op.Mul(&t6, &t2, ¶ms.C) // t6 = t2 * A24-
|
||||
op.Mul(&t2, &t2, &t6) // t2 = t2 * t6
|
||||
op.Sub(&t3, &t2, &t3) // t3 = t2 - t3
|
||||
op.Sub(&t2, &t5, &t6) // t2 = t5 - t6
|
||||
op.Mul(&t1, &t2, &t1) // t1 = t2 * t1
|
||||
op.Add(&t2, &t3, &t1) // t2 = t3 + t1
|
||||
op.Square(&t2, &t2) // t2 = t2^2
|
||||
op.Mul(x, &t2, &t4) // X3p = t2 * t4
|
||||
op.Sub(&t1, &t3, &t1) // t1 = t3 - t1
|
||||
op.Square(&t1, &t1) // t1 = t1^2
|
||||
op.Mul(z, &t1, &t0) // Z3p = t1 * t0
|
||||
}
|
||||
}
|
||||
|
||||
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
|
||||
//
|
||||
// All xi, yi must be distinct.
|
||||
func (c *CurveOperations) Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2Element) {
|
||||
var x1x2, t Fp2Element
|
||||
var op = c.Params.Op
|
||||
|
||||
op.Mul(&x1x2, x1, x2) // x1*x2
|
||||
op.Mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
|
||||
op.Inv(&t, &t)
|
||||
op.Mul(y1, &t, x2) // 1/x1
|
||||
op.Mul(y1, y1, x3)
|
||||
op.Mul(y2, &t, x1) // 1/x2
|
||||
op.Mul(y2, y2, x3)
|
||||
op.Mul(y3, &t, &x1x2) // 1/x3
|
||||
}
|
||||
|
||||
// ScalarMul3Pt is a right-to-left point multiplication that given the
|
||||
// x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
|
||||
// nbits must be smaller or equal to len(scalar).
|
||||
func (c *CurveOperations) ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
|
||||
var R0, R2, R1 ProjectivePoint
|
||||
var op = c.Params.Op
|
||||
aPlus2Over4 := c.CalcAplus2Over4(cparams)
|
||||
R1 = *P
|
||||
R2 = *PmQ
|
||||
R0 = *Q
|
||||
|
||||
// Iterate over the bits of the scalar, bottom to top
|
||||
prevBit := uint8(0)
|
||||
for i := uint(0); i < nbits; i++ {
|
||||
bit := (scalar[i>>3] >> (i & 7) & 1)
|
||||
swap := prevBit ^ bit
|
||||
prevBit = bit
|
||||
op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
|
||||
R0, R2 = c.xDblAdd(&R0, &R2, &R1, &aPlus2Over4)
|
||||
}
|
||||
op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
|
||||
return R1
|
||||
}
|
||||
|
||||
// Convert the input to wire format.
|
||||
//
|
||||
// The output byte slice must be at least 2*bytelen(p) bytes long.
|
||||
func (c *CurveOperations) Fp2ToBytes(output []byte, fp2 *Fp2Element) {
|
||||
if len(output) < 2*c.Params.Bytelen {
|
||||
panic("output byte slice too short")
|
||||
}
|
||||
var a Fp2Element
|
||||
c.Params.Op.FromMontgomery(fp2, &a)
|
||||
|
||||
// convert to bytes in little endian form
|
||||
for i := 0; i < c.Params.Bytelen; i++ {
|
||||
// set i = j*8 + k
|
||||
fp2 := i / 8
|
||||
k := uint64(i % 8)
|
||||
output[i] = byte(a.A[fp2] >> (8 * k))
|
||||
output[i+c.Params.Bytelen] = byte(a.B[fp2] >> (8 * k))
|
||||
}
|
||||
}
|
||||
|
||||
// Read 2*bytelen(p) bytes into the given ExtensionFieldElement.
|
||||
//
|
||||
// It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long.
|
||||
func (c *CurveOperations) Fp2FromBytes(fp2 *Fp2Element, input []byte) {
|
||||
if len(input) < 2*c.Params.Bytelen {
|
||||
panic("input byte slice too short")
|
||||
}
|
||||
|
||||
for i := 0; i < c.Params.Bytelen; i++ {
|
||||
j := i / 8
|
||||
k := uint64(i % 8)
|
||||
fp2.A[j] |= uint64(input[i]) << (8 * k)
|
||||
fp2.B[j] |= uint64(input[i+c.Params.Bytelen]) << (8 * k)
|
||||
}
|
||||
c.Params.Op.ToMontgomery(fp2)
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Mechnisms used for isogeny calculations
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
// Constructs isogeny3 objects
|
||||
func Newisogeny3(op FieldOps) Isogeny {
|
||||
return &isogeny3{Field: op}
|
||||
}
|
||||
|
||||
// Constructs isogeny4 objects
|
||||
func Newisogeny4(op FieldOps) Isogeny {
|
||||
return &isogeny4{isogeny3: isogeny3{Field: op}}
|
||||
}
|
||||
|
||||
// Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the
|
||||
// three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C').
|
||||
//
|
||||
// Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C
|
||||
// Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3>
|
||||
// * Isogeny phi with constants in F_p^2
|
||||
func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
|
||||
var t0, t1, t2, t3, t4 Fp2Element
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
|
||||
op := phi.Field
|
||||
op.Sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
|
||||
op.Square(&t0, K1) // t0 = K1^2
|
||||
op.Add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
|
||||
op.Square(&t1, K2) // t1 = K2^2
|
||||
op.Add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
op.Add(&t3, K1, K2) // t3 = K1 + K2
|
||||
op.Square(&t3, &t3) // t3 = t3^2
|
||||
op.Sub(&t3, &t3, &t2) // t3 = t3 - t2
|
||||
op.Add(&t2, &t1, &t3) // t2 = t1 + t3
|
||||
op.Add(&t3, &t3, &t0) // t3 = t3 + t0
|
||||
op.Add(&t4, &t3, &t0) // t4 = t3 + t0
|
||||
op.Add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
op.Add(&t4, &t1, &t4) // t4 = t1 + t4
|
||||
op.Mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
|
||||
op.Add(&t4, &t1, &t2) // t4 = t1 + t2
|
||||
op.Add(&t4, &t4, &t4) // t4 = t4 + t4
|
||||
op.Add(&t4, &t0, &t4) // t4 = t0 + t4
|
||||
op.Mul(&t4, &t3, &t4) // t4 = t3 * t4
|
||||
op.Sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
|
||||
op.Add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0
|
||||
return coefEq
|
||||
}
|
||||
|
||||
// Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate
|
||||
// of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C').
|
||||
//
|
||||
// The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve
|
||||
// parameters are returned by the GenerateCurve function used to construct phi.
|
||||
func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
|
||||
var t0, t1, t2 Fp2Element
|
||||
var q ProjectivePoint
|
||||
var K1, K2 = &phi.K1, &phi.K2
|
||||
var px, pz = &p.X, &p.Z
|
||||
|
||||
op := phi.Field
|
||||
op.Add(&t0, px, pz) // t0 = XQ + ZQ
|
||||
op.Sub(&t1, px, pz) // t1 = XQ - ZQ
|
||||
op.Mul(&t0, K1, &t0) // t2 = K1 * t0
|
||||
op.Mul(&t1, K2, &t1) // t1 = K2 * t1
|
||||
op.Add(&t2, &t0, &t1) // t2 = t0 + t1
|
||||
op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
|
||||
op.Square(&t2, &t2) // t2 = t2 ^ 2
|
||||
op.Square(&t0, &t0) // t0 = t0 ^ 2
|
||||
op.Mul(&q.X, px, &t2) // XQ'= XQ * t2
|
||||
op.Mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0
|
||||
return q
|
||||
}
|
||||
|
||||
// Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the
|
||||
// four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C').
|
||||
//
|
||||
// Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C
|
||||
// Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4>
|
||||
// * Isogeny phi with constants in F_p^2
|
||||
func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
|
||||
var coefEq CurveCoefficientsEquiv
|
||||
var xp4, zp4 = &p.X, &p.Z
|
||||
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
|
||||
|
||||
op := phi.Field
|
||||
op.Sub(K2, xp4, zp4)
|
||||
op.Add(K3, xp4, zp4)
|
||||
op.Square(K1, zp4)
|
||||
op.Add(K1, K1, K1)
|
||||
op.Square(&coefEq.C, K1)
|
||||
op.Add(K1, K1, K1)
|
||||
op.Square(&coefEq.A, xp4)
|
||||
op.Add(&coefEq.A, &coefEq.A, &coefEq.A)
|
||||
op.Square(&coefEq.A, &coefEq.A)
|
||||
return coefEq
|
||||
}
|
||||
|
||||
// Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate
|
||||
// of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C').
|
||||
//
|
||||
// Input: Isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C
|
||||
// Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0
|
||||
func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
|
||||
var t0, t1 Fp2Element
|
||||
var q = *p
|
||||
var xq, zq = &q.X, &q.Z
|
||||
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
|
||||
|
||||
op := phi.Field
|
||||
op.Add(&t0, xq, zq)
|
||||
op.Sub(&t1, xq, zq)
|
||||
op.Mul(xq, &t0, K2)
|
||||
op.Mul(zq, &t1, K3)
|
||||
op.Mul(&t0, &t0, &t1)
|
||||
op.Mul(&t0, &t0, K1)
|
||||
op.Add(&t1, xq, zq)
|
||||
op.Sub(zq, xq, zq)
|
||||
op.Square(&t1, &t1)
|
||||
op.Square(zq, zq)
|
||||
op.Add(xq, &t0, &t1)
|
||||
op.Sub(&t0, zq, &t0)
|
||||
op.Mul(xq, xq, &t1)
|
||||
op.Mul(zq, zq, &t0)
|
||||
return q
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Utils
|
||||
-------------------------------------------------------------------------*/
|
||||
func (point *ProjectivePoint) ToAffine(c *CurveOperations) *Fp2Element {
|
||||
var affine_x Fp2Element
|
||||
c.Params.Op.Inv(&affine_x, &point.Z)
|
||||
c.Params.Op.Mul(&affine_x, &affine_x, &point.X)
|
||||
return &affine_x
|
||||
}
|
||||
|
||||
// Cleans data in fp
|
||||
func (fp *Fp2Element) Zeroize() {
|
||||
// Zeroizing in 2 seperated loops tells compiler to
|
||||
// use fast runtime.memclr()
|
||||
for i := range fp.A {
|
||||
fp.A[i] = 0
|
||||
}
|
||||
for i := range fp.B {
|
||||
fp.B[i] = 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package internal
|
||||
|
||||
const (
|
||||
FP_MAX_WORDS = 12 // Currently p751.NumWords
|
||||
)
|
||||
|
||||
// Representation of an element of the base field F_p.
|
||||
//
|
||||
// No particular meaning is assigned to the representation -- it could represent
|
||||
// an element in Montgomery form, or not. Tracking the meaning of the field
|
||||
// element is left to higher types.
|
||||
type FpElement [FP_MAX_WORDS]uint64
|
||||
|
||||
// Represents an intermediate product of two elements of the base field F_p.
|
||||
type FpElementX2 [2 * FP_MAX_WORDS]uint64
|
||||
|
||||
// Represents an element of the extended field Fp^2 = Fp(x+i)
|
||||
type Fp2Element struct {
|
||||
A FpElement
|
||||
B FpElement
|
||||
}
|
||||
|
||||
type DomainParams struct {
|
||||
// P, Q and R=P-Q base points
|
||||
Affine_P, Affine_Q, Affine_R Fp2Element
|
||||
// Size of a compuatation strategy for x-torsion group
|
||||
IsogenyStrategy []uint32
|
||||
// Max size of secret key for x-torsion group
|
||||
SecretBitLen uint
|
||||
// Max size of secret key for x-torsion group
|
||||
SecretByteLen uint
|
||||
}
|
||||
|
||||
type SidhParams struct {
|
||||
Id uint8
|
||||
// Bytelen of P
|
||||
Bytelen int
|
||||
// The public key size, in bytes.
|
||||
PublicKeySize int
|
||||
// The shared secret size, in bytes.
|
||||
SharedSecretSize uint
|
||||
// 2- and 3-torsion group parameter definitions
|
||||
A, B DomainParams
|
||||
// Precomputed identity element in the Fp2 in Montgomery domain
|
||||
OneFp2 Fp2Element
|
||||
// Precomputed 1/2 in the Fp2 in Montgomery domain
|
||||
HalfFp2 Fp2Element
|
||||
// Length of SIKE secret message. Must be one of {24,32,40},
|
||||
// depending on size of prime field used (see [SIKE], 1.4 and 5.1)
|
||||
MsgLen uint
|
||||
// Length of SIKE ephemeral KEM key (see [SIKE], 1.4 and 5.1)
|
||||
KemSize uint
|
||||
// Access to field arithmetic
|
||||
Op FieldOps
|
||||
}
|
||||
|
||||
// Interface for working with isogenies.
|
||||
type Isogeny interface {
|
||||
// Given a torsion point on a curve computes isogenous curve.
|
||||
// Returns curve coefficients (A:C), so that E_(A/C) = E_(A/C)/<P>,
|
||||
// where P is a provided projective point. Sets also isogeny constants
|
||||
// that are needed for isogeny evaluation.
|
||||
GenerateCurve(*ProjectivePoint) CurveCoefficientsEquiv
|
||||
// Evaluates isogeny at caller provided point. Requires isogeny curve constants
|
||||
// to be earlier computed by GenerateCurve.
|
||||
EvaluatePoint(*ProjectivePoint) ProjectivePoint
|
||||
}
|
||||
|
||||
// Stores curve projective parameters equivalent to A/C. Meaning of the
|
||||
// values depends on the context. When working with isogenies over
|
||||
// subgroup that are powers of:
|
||||
// * three then (A:C) ~ (A+2C:A-2C)
|
||||
// * four then (A:C) ~ (A+2C: 4C)
|
||||
// See Appendix A of SIKE for more details
|
||||
type CurveCoefficientsEquiv struct {
|
||||
A Fp2Element
|
||||
C Fp2Element
|
||||
}
|
||||
|
||||
// A point on the projective line P^1(F_{p^2}).
|
||||
//
|
||||
// This represents a point on the Kummer line of a Montgomery curve. The
|
||||
// curve is specified by a ProjectiveCurveParameters struct.
|
||||
type ProjectivePoint struct {
|
||||
X Fp2Element
|
||||
Z Fp2Element
|
||||
}
|
||||
|
||||
// A point on the projective line P^1(F_{p^2}).
|
||||
//
|
||||
// This is used to work projectively with the curve coefficients.
|
||||
type ProjectiveCurveParameters struct {
|
||||
A Fp2Element
|
||||
C Fp2Element
|
||||
}
|
||||
|
||||
// Stores Isogeny 3 curve constants
|
||||
type isogeny3 struct {
|
||||
Field FieldOps
|
||||
K1 Fp2Element
|
||||
K2 Fp2Element
|
||||
}
|
||||
|
||||
// Stores Isogeny 4 curve constants
|
||||
type isogeny4 struct {
|
||||
isogeny3
|
||||
K3 Fp2Element
|
||||
}
|
||||
|
||||
type FieldOps interface {
|
||||
// Set res = lhs + rhs.
|
||||
//
|
||||
// Allowed to overlap lhs or rhs with res.
|
||||
Add(res, lhs, rhs *Fp2Element)
|
||||
|
||||
// Set res = lhs - rhs.
|
||||
//
|
||||
// Allowed to overlap lhs or rhs with res.
|
||||
Sub(res, lhs, rhs *Fp2Element)
|
||||
|
||||
// Set res = lhs * rhs.
|
||||
//
|
||||
// Allowed to overlap lhs or rhs with res.
|
||||
Mul(res, lhs, rhs *Fp2Element)
|
||||
// Set res = x * x
|
||||
//
|
||||
// Allowed to overlap res with x.
|
||||
Square(res, x *Fp2Element)
|
||||
// Set res = 1/x
|
||||
//
|
||||
// Allowed to overlap res with x.
|
||||
Inv(res, x *Fp2Element)
|
||||
// If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y).
|
||||
CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8)
|
||||
// Converts Fp2Element to Montgomery domain (x*R mod p)
|
||||
ToMontgomery(x *Fp2Element)
|
||||
// Converts 'a' in montgomery domain to element from Fp2Element
|
||||
// and stores it in 'x'
|
||||
FromMontgomery(x *Fp2Element, a *Fp2Element)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package utils
|
||||
|
||||
type x86 struct {
|
||||
// Signals support for MULX which is in BMI2
|
||||
HasBMI2 bool
|
||||
|
||||
// Signals support for ADX
|
||||
HasADX bool
|
||||
}
|
||||
|
||||
var X86 x86
|
||||
@@ -0,0 +1,29 @@
|
||||
// +build amd64,!noasm
|
||||
|
||||
// Sets capabilities flags for x86 according to information received from
|
||||
// CPUID. It was written in accordance with
|
||||
// "Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A".
|
||||
// https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
|
||||
|
||||
package utils
|
||||
|
||||
// Performs CPUID and returns values of registers
|
||||
// go:nosplit
|
||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
|
||||
// Returns true in case bit 'n' in 'bits' is set, otherwise false
|
||||
func bitn(bits uint32, n uint8) bool {
|
||||
return (bits>>n)&1 == 1
|
||||
}
|
||||
|
||||
func init() {
|
||||
// CPUID returns max possible input that can be requested
|
||||
max, _, _, _ := cpuid(0, 0)
|
||||
if max < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
_, ebx, _, _ := cpuid(7, 0)
|
||||
X86.HasBMI2 = bitn(ebx, 8)
|
||||
X86.HasADX = bitn(ebx, 19)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// +build amd64,!noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·cpuid(SB), NOSPLIT, $0-4
|
||||
MOVL eaxArg+0(FP), AX
|
||||
MOVL ecxArg+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, eax+8(FP)
|
||||
MOVL BX, ebx+12(FP)
|
||||
MOVL CX, ecx+16(FP)
|
||||
MOVL DX, edx+20(FP)
|
||||
RET
|
||||
Reference in New Issue
Block a user