mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-06-05 10:39:14 -04:00
move vendor to external
This commit is contained in:
57
external/github.com/cloudflare/sidh/LICENSE
vendored
Normal file
57
external/github.com/cloudflare/sidh/LICENSE
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
Copyright (c) 2017 Cloudflare. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Cloudflare nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
========================================================================
|
||||
|
||||
The x64 field arithmetic implementation was derived from the Microsoft Research
|
||||
SIDH implementation, <https://v2ray.com/core/external/github.com/Microsoft/PQCrypto-SIDH>, available
|
||||
under the following license:
|
||||
|
||||
========================================================================
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
66
external/github.com/cloudflare/sidh/internal/arith/generic.go
vendored
Normal file
66
external/github.com/cloudflare/sidh/internal/arith/generic.go
vendored
Normal file
@@ -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
|
||||
}
|
||||
440
external/github.com/cloudflare/sidh/internal/isogeny/curve_ops.go
vendored
Normal file
440
external/github.com/cloudflare/sidh/internal/isogeny/curve_ops.go
vendored
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
140
external/github.com/cloudflare/sidh/internal/isogeny/types.go
vendored
Normal file
140
external/github.com/cloudflare/sidh/internal/isogeny/types.go
vendored
Normal file
@@ -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)
|
||||
}
|
||||
11
external/github.com/cloudflare/sidh/internal/utils/cpu.go
vendored
Normal file
11
external/github.com/cloudflare/sidh/internal/utils/cpu.go
vendored
Normal file
@@ -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
|
||||
29
external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.go
vendored
Normal file
29
external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.go
vendored
Normal file
@@ -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)
|
||||
}
|
||||
13
external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.s
vendored
Normal file
13
external/github.com/cloudflare/sidh/internal/utils/cpuid_amd64.s
vendored
Normal file
@@ -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
|
||||
1708
external/github.com/cloudflare/sidh/p503/arith_amd64.s
vendored
Normal file
1708
external/github.com/cloudflare/sidh/p503/arith_amd64.s
vendored
Normal file
File diff suppressed because it is too large
Load Diff
802
external/github.com/cloudflare/sidh/p503/arith_arm64.s
vendored
Normal file
802
external/github.com/cloudflare/sidh/p503/arith_arm64.s
vendored
Normal file
@@ -0,0 +1,802 @@
|
||||
// +build arm64,!noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·fp503ConditionalSwap(SB), NOSPLIT, $0-17
|
||||
MOVD x+0(FP), R0
|
||||
MOVD y+8(FP), R1
|
||||
MOVB choice+16(FP), R2
|
||||
|
||||
// Set flags
|
||||
// If choice is not 0 or 1, this implementation will swap completely
|
||||
CMP $0, R2
|
||||
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R5, R6)
|
||||
CSEL EQ, R3, R5, R7
|
||||
CSEL EQ, R4, R6, R8
|
||||
STP (R7, R8), 0(R0)
|
||||
CSEL NE, R3, R5, R9
|
||||
CSEL NE, R4, R6, R10
|
||||
STP (R9, R10), 0(R1)
|
||||
|
||||
LDP 16(R0), (R3, R4)
|
||||
LDP 16(R1), (R5, R6)
|
||||
CSEL EQ, R3, R5, R7
|
||||
CSEL EQ, R4, R6, R8
|
||||
STP (R7, R8), 16(R0)
|
||||
CSEL NE, R3, R5, R9
|
||||
CSEL NE, R4, R6, R10
|
||||
STP (R9, R10), 16(R1)
|
||||
|
||||
LDP 32(R0), (R3, R4)
|
||||
LDP 32(R1), (R5, R6)
|
||||
CSEL EQ, R3, R5, R7
|
||||
CSEL EQ, R4, R6, R8
|
||||
STP (R7, R8), 32(R0)
|
||||
CSEL NE, R3, R5, R9
|
||||
CSEL NE, R4, R6, R10
|
||||
STP (R9, R10), 32(R1)
|
||||
|
||||
LDP 48(R0), (R3, R4)
|
||||
LDP 48(R1), (R5, R6)
|
||||
CSEL EQ, R3, R5, R7
|
||||
CSEL EQ, R4, R6, R8
|
||||
STP (R7, R8), 48(R0)
|
||||
CSEL NE, R3, R5, R9
|
||||
CSEL NE, R4, R6, R10
|
||||
STP (R9, R10), 48(R1)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503AddReduced(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
// Load first summand into R3-R10
|
||||
// Add first summand and second summand and store result in R3-R10
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 16(R1), (R13, R14)
|
||||
ADDS R11, R3
|
||||
ADCS R12, R4
|
||||
ADCS R13, R5
|
||||
ADCS R14, R6
|
||||
|
||||
LDP 32(R0), (R7, R8)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R0), (R9, R10)
|
||||
LDP 48(R1), (R13, R14)
|
||||
ADCS R11, R7
|
||||
ADCS R12, R8
|
||||
ADCS R13, R9
|
||||
ADC R14, R10
|
||||
|
||||
// Subtract 2 * p503 in R11-R17 from the result in R3-R10
|
||||
LDP ·p503x2+0(SB), (R11, R12)
|
||||
LDP ·p503x2+24(SB), (R13, R14)
|
||||
SUBS R11, R3
|
||||
SBCS R12, R4
|
||||
LDP ·p503x2+40(SB), (R15, R16)
|
||||
SBCS R12, R5
|
||||
SBCS R13, R6
|
||||
MOVD ·p503x2+56(SB), R17
|
||||
SBCS R14, R7
|
||||
SBCS R15, R8
|
||||
SBCS R16, R9
|
||||
SBCS R17, R10
|
||||
SBC ZR, ZR, R19
|
||||
|
||||
// If x + y - 2 * p503 < 0, R19 is 1 and 2 * p503 should be added
|
||||
AND R19, R11
|
||||
AND R19, R12
|
||||
AND R19, R13
|
||||
AND R19, R14
|
||||
AND R19, R15
|
||||
AND R19, R16
|
||||
AND R19, R17
|
||||
|
||||
ADDS R11, R3
|
||||
ADCS R12, R4
|
||||
STP (R3, R4), 0(R2)
|
||||
ADCS R12, R5
|
||||
ADCS R13, R6
|
||||
STP (R5, R6), 16(R2)
|
||||
ADCS R14, R7
|
||||
ADCS R15, R8
|
||||
STP (R7, R8), 32(R2)
|
||||
ADCS R16, R9
|
||||
ADC R17, R10
|
||||
STP (R9, R10), 48(R2)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503SubReduced(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
// Load x into R3-R10
|
||||
// Subtract y from x and store result in R3-R10
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 16(R1), (R13, R14)
|
||||
SUBS R11, R3
|
||||
SBCS R12, R4
|
||||
SBCS R13, R5
|
||||
SBCS R14, R6
|
||||
|
||||
LDP 32(R0), (R7, R8)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R0), (R9, R10)
|
||||
LDP 48(R1), (R13, R14)
|
||||
SBCS R11, R7
|
||||
SBCS R12, R8
|
||||
SBCS R13, R9
|
||||
SBCS R14, R10
|
||||
SBC ZR, ZR, R19
|
||||
|
||||
// If x - y < 0, R19 is 1 and 2 * p503 should be added
|
||||
LDP ·p503x2+0(SB), (R11, R12)
|
||||
LDP ·p503x2+24(SB), (R13, R14)
|
||||
AND R19, R11
|
||||
AND R19, R12
|
||||
LDP ·p503x2+40(SB), (R15, R16)
|
||||
AND R19, R13
|
||||
AND R19, R14
|
||||
MOVD ·p503x2+56(SB), R17
|
||||
AND R19, R15
|
||||
AND R19, R16
|
||||
AND R19, R17
|
||||
|
||||
ADDS R11, R3
|
||||
ADCS R12, R4
|
||||
STP (R3, R4), 0(R2)
|
||||
ADCS R12, R5
|
||||
ADCS R13, R6
|
||||
STP (R5, R6), 16(R2)
|
||||
ADCS R14, R7
|
||||
ADCS R15, R8
|
||||
STP (R7, R8), 32(R2)
|
||||
ADCS R16, R9
|
||||
ADC R17, R10
|
||||
STP (R9, R10), 48(R2)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503AddLazy(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
// Load first summand into R3-R10
|
||||
// Add first summand and second summand and store result in R3-R10
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 16(R1), (R13, R14)
|
||||
ADDS R11, R3
|
||||
ADCS R12, R4
|
||||
STP (R3, R4), 0(R2)
|
||||
ADCS R13, R5
|
||||
ADCS R14, R6
|
||||
STP (R5, R6), 16(R2)
|
||||
|
||||
LDP 32(R0), (R7, R8)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R0), (R9, R10)
|
||||
LDP 48(R1), (R13, R14)
|
||||
ADCS R11, R7
|
||||
ADCS R12, R8
|
||||
STP (R7, R8), 32(R2)
|
||||
ADCS R13, R9
|
||||
ADC R14, R10
|
||||
STP (R9, R10), 48(R2)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503X2AddLazy(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 16(R1), (R13, R14)
|
||||
ADDS R11, R3
|
||||
ADCS R12, R4
|
||||
STP (R3, R4), 0(R2)
|
||||
ADCS R13, R5
|
||||
ADCS R14, R6
|
||||
STP (R5, R6), 16(R2)
|
||||
|
||||
LDP 32(R0), (R7, R8)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R0), (R9, R10)
|
||||
LDP 48(R1), (R13, R14)
|
||||
ADCS R11, R7
|
||||
ADCS R12, R8
|
||||
STP (R7, R8), 32(R2)
|
||||
ADCS R13, R9
|
||||
ADCS R14, R10
|
||||
STP (R9, R10), 48(R2)
|
||||
|
||||
LDP 64(R0), (R3, R4)
|
||||
LDP 64(R1), (R11, R12)
|
||||
LDP 80(R0), (R5, R6)
|
||||
LDP 80(R1), (R13, R14)
|
||||
ADCS R11, R3
|
||||
ADCS R12, R4
|
||||
STP (R3, R4), 64(R2)
|
||||
ADCS R13, R5
|
||||
ADCS R14, R6
|
||||
STP (R5, R6), 80(R2)
|
||||
|
||||
LDP 96(R0), (R7, R8)
|
||||
LDP 96(R1), (R11, R12)
|
||||
LDP 112(R0), (R9, R10)
|
||||
LDP 112(R1), (R13, R14)
|
||||
ADCS R11, R7
|
||||
ADCS R12, R8
|
||||
STP (R7, R8), 96(R2)
|
||||
ADCS R13, R9
|
||||
ADC R14, R10
|
||||
STP (R9, R10), 112(R2)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503X2SubLazy(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 16(R1), (R13, R14)
|
||||
SUBS R11, R3
|
||||
SBCS R12, R4
|
||||
STP (R3, R4), 0(R2)
|
||||
SBCS R13, R5
|
||||
SBCS R14, R6
|
||||
STP (R5, R6), 16(R2)
|
||||
|
||||
LDP 32(R0), (R7, R8)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R0), (R9, R10)
|
||||
LDP 48(R1), (R13, R14)
|
||||
SBCS R11, R7
|
||||
SBCS R12, R8
|
||||
STP (R7, R8), 32(R2)
|
||||
SBCS R13, R9
|
||||
SBCS R14, R10
|
||||
STP (R9, R10), 48(R2)
|
||||
|
||||
LDP 64(R0), (R3, R4)
|
||||
LDP 64(R1), (R11, R12)
|
||||
LDP 80(R0), (R5, R6)
|
||||
LDP 80(R1), (R13, R14)
|
||||
SBCS R11, R3
|
||||
SBCS R12, R4
|
||||
SBCS R13, R5
|
||||
SBCS R14, R6
|
||||
|
||||
LDP 96(R0), (R7, R8)
|
||||
LDP 96(R1), (R11, R12)
|
||||
LDP 112(R0), (R9, R10)
|
||||
LDP 112(R1), (R13, R14)
|
||||
SBCS R11, R7
|
||||
SBCS R12, R8
|
||||
SBCS R13, R9
|
||||
SBCS R14, R10
|
||||
SBC ZR, ZR, R15
|
||||
|
||||
// If x - y < 0, R15 is 1 and p503 should be added
|
||||
LDP ·p503+16(SB), (R16, R17)
|
||||
LDP ·p503+32(SB), (R19, R20)
|
||||
AND R15, R16
|
||||
AND R15, R17
|
||||
LDP ·p503+48(SB), (R21, R22)
|
||||
AND R15, R19
|
||||
AND R15, R20
|
||||
AND R15, R21
|
||||
AND R15, R22
|
||||
|
||||
ADDS R16, R3
|
||||
ADCS R16, R4
|
||||
STP (R3, R4), 64(R2)
|
||||
ADCS R16, R5
|
||||
ADCS R17, R6
|
||||
STP (R5, R6), 80(R2)
|
||||
ADCS R19, R7
|
||||
ADCS R20, R8
|
||||
STP (R7, R8), 96(R2)
|
||||
ADCS R21, R9
|
||||
ADC R22, R10
|
||||
STP (R9, R10), 112(R2)
|
||||
|
||||
RET
|
||||
|
||||
// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high)
|
||||
// Z0 is not actually touched
|
||||
// Result of (X0-X1) * (Y0-Y1) will be in Z0-Z3
|
||||
// Inputs get overwritten, except for X1
|
||||
#define mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, Z2, Z3, T0) \
|
||||
MUL X1, Y0, X0 \
|
||||
UMULH X1, Y0, Y0 \
|
||||
ADDS Z3, Z1 \
|
||||
ADC ZR, Z2 \
|
||||
\
|
||||
MUL Y1, X1, T0 \
|
||||
UMULH Y1, X1, Y1 \
|
||||
ADDS X0, Z1 \
|
||||
ADCS Y0, Z2 \
|
||||
ADC ZR, ZR, Z3 \
|
||||
\
|
||||
ADDS T0, Z2 \
|
||||
ADC Y1, Z3
|
||||
|
||||
// Expects that X points to (X0-X1)
|
||||
// Result of (X0-X3) * (Y0-Y3) will be in Z0-Z7
|
||||
// Inputs get overwritten, except X2-X3 and Y2-Y3
|
||||
#define mul256x256karatsuba(X, X0, X1, X2, X3, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, Z6, Z7, T0, T1)\
|
||||
ADDS X2, X0 \ // xH + xL, destroys xL
|
||||
ADCS X3, X1 \
|
||||
ADCS ZR, ZR, T0 \
|
||||
\
|
||||
ADDS Y2, Y0, Z6 \ // yH + yL
|
||||
ADCS Y3, Y1, T1 \
|
||||
ADC ZR, ZR, Z7 \
|
||||
\
|
||||
SUB T0, ZR, Z2 \
|
||||
SUB Z7, ZR, Z3 \
|
||||
AND Z7, T0 \ // combined carry
|
||||
\
|
||||
AND Z2, Z6, Z0 \ // masked(yH + yL)
|
||||
AND Z2, T1, Z1 \
|
||||
\
|
||||
AND Z3, X0, Z4 \ // masked(xH + xL)
|
||||
AND Z3, X1, Z5 \
|
||||
\
|
||||
MUL Z6, X0, Z2 \
|
||||
MUL T1, X0, Z3 \
|
||||
\
|
||||
ADDS Z4, Z0 \
|
||||
UMULH T1, X0, Z4 \
|
||||
ADCS Z5, Z1 \
|
||||
UMULH Z6, X0, Z5 \
|
||||
ADC ZR, T0 \
|
||||
\ // (xH + xL) * (yH + yL)
|
||||
mul128x128comba(X0, X1, Z6, T1, Z2, Z3, Z4, Z5, Z7)\
|
||||
\
|
||||
LDP 0+X, (X0, X1) \
|
||||
\
|
||||
ADDS Z0, Z4 \
|
||||
UMULH Y0, X0, Z7 \
|
||||
UMULH Y1, X0, T1 \
|
||||
ADCS Z1, Z5 \
|
||||
MUL Y0, X0, Z0 \
|
||||
MUL Y1, X0, Z1 \
|
||||
ADC ZR, T0 \
|
||||
\ // xL * yL
|
||||
mul128x128comba(X0, X1, Y0, Y1, Z0, Z1, T1, Z7, Z6)\
|
||||
\
|
||||
MUL Y2, X2, X0 \
|
||||
UMULH Y2, X2, Y0 \
|
||||
SUBS Z0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL
|
||||
SBCS Z1, Z3 \
|
||||
SBCS T1, Z4 \
|
||||
MUL Y3, X2, X1 \
|
||||
UMULH Y3, X2, Z6 \
|
||||
SBCS Z7, Z5 \
|
||||
SBCS ZR, T0 \
|
||||
\ // xH * yH
|
||||
mul128x128comba(X2, X3, Y2, Y3, X0, X1, Z6, Y0, Y1)\
|
||||
\
|
||||
SUBS X0, Z2 \ // (xH + xL) * (yH + yL) - xL * yL - xH * yH
|
||||
SBCS X1, Z3 \
|
||||
SBCS Z6, Z4 \
|
||||
SBCS Y0, Z5 \
|
||||
SBCS ZR, T0 \
|
||||
\
|
||||
ADDS T1, Z2 \ // (xH * yH) * 2^256 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^128 + xL * yL
|
||||
ADCS Z7, Z3 \
|
||||
ADCS X0, Z4 \
|
||||
ADCS X1, Z5 \
|
||||
ADCS T0, Z6 \
|
||||
ADC Y0, ZR, Z7
|
||||
|
||||
|
||||
// This implements two-level Karatsuba with a 128x128 Comba multiplier
|
||||
// at the bottom
|
||||
TEXT ·fp503Mul(SB), NOSPLIT, $0-24
|
||||
MOVD z+0(FP), R2
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
// Load xL in R3-R6, xH in R7-R10
|
||||
// (xH + xL) in R25-R29
|
||||
LDP 0(R0), (R3, R4)
|
||||
LDP 32(R0), (R7, R8)
|
||||
ADDS R3, R7, R25
|
||||
ADCS R4, R8, R26
|
||||
LDP 16(R0), (R5, R6)
|
||||
LDP 48(R0), (R9, R10)
|
||||
ADCS R5, R9, R27
|
||||
ADCS R6, R10, R29
|
||||
ADC ZR, ZR, R7
|
||||
|
||||
// Load yL in R11-R14, yH in R15-19
|
||||
// (yH + yL) in R11-R14, destroys yL
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 32(R1), (R15, R16)
|
||||
ADDS R15, R11
|
||||
ADCS R16, R12
|
||||
LDP 16(R1), (R13, R14)
|
||||
LDP 48(R1), (R17, R19)
|
||||
ADCS R17, R13
|
||||
ADCS R19, R14
|
||||
ADC ZR, ZR, R8
|
||||
|
||||
// Compute maskes and combined carry
|
||||
SUB R7, ZR, R9
|
||||
SUB R8, ZR, R10
|
||||
AND R8, R7
|
||||
|
||||
// masked(yH + yL)
|
||||
AND R9, R11, R15
|
||||
AND R9, R12, R16
|
||||
AND R9, R13, R17
|
||||
AND R9, R14, R19
|
||||
|
||||
// masked(xH + xL)
|
||||
AND R10, R25, R20
|
||||
AND R10, R26, R21
|
||||
AND R10, R27, R22
|
||||
AND R10, R29, R23
|
||||
|
||||
// masked(xH + xL) + masked(yH + yL) in R15-R19
|
||||
ADDS R20, R15
|
||||
ADCS R21, R16
|
||||
ADCS R22, R17
|
||||
ADCS R23, R19
|
||||
ADC ZR, R7
|
||||
|
||||
// Use z as temporary storage
|
||||
STP (R25, R26), 0(R2)
|
||||
|
||||
// (xH + xL) * (yH + yL)
|
||||
mul256x256karatsuba(0(R2), R25, R26, R27, R29, R11, R12, R13, R14, R8, R9, R10, R20, R21, R22, R23, R24, R0, R1)
|
||||
|
||||
MOVD x+8(FP), R0
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
ADDS R21, R15
|
||||
ADCS R22, R16
|
||||
ADCS R23, R17
|
||||
ADCS R24, R19
|
||||
ADC ZR, R7
|
||||
|
||||
// Load yL in R11-R14
|
||||
LDP 0(R1), (R11, R12)
|
||||
LDP 16(R1), (R13, R14)
|
||||
|
||||
// xL * yL
|
||||
mul256x256karatsuba(0(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R1, R2)
|
||||
|
||||
MOVD z+0(FP), R2
|
||||
MOVD y+16(FP), R1
|
||||
|
||||
// (xH + xL) * (yH + yL) - xL * yL
|
||||
SUBS R21, R8
|
||||
SBCS R22, R9
|
||||
STP (R21, R22), 0(R2)
|
||||
SBCS R23, R10
|
||||
SBCS R24, R20
|
||||
STP (R23, R24), 16(R2)
|
||||
SBCS R25, R15
|
||||
SBCS R26, R16
|
||||
SBCS R27, R17
|
||||
SBCS R29, R19
|
||||
SBC ZR, R7
|
||||
|
||||
// Load xH in R3-R6, yH in R11-R14
|
||||
LDP 32(R0), (R3, R4)
|
||||
LDP 48(R0), (R5, R6)
|
||||
LDP 32(R1), (R11, R12)
|
||||
LDP 48(R1), (R13, R14)
|
||||
|
||||
ADDS R25, R8
|
||||
ADCS R26, R9
|
||||
ADCS R27, R10
|
||||
ADCS R29, R20
|
||||
ADC ZR, ZR, R1
|
||||
|
||||
MOVD R20, 32(R2)
|
||||
|
||||
// xH * yH
|
||||
mul256x256karatsuba(32(R0), R3, R4, R5, R6, R11, R12, R13, R14, R21, R22, R23, R24, R25, R26, R27, R29, R2, R20)
|
||||
NEG R1, R1
|
||||
|
||||
MOVD z+0(FP), R2
|
||||
MOVD 32(R2), R20
|
||||
|
||||
// (xH + xL) * (yH + yL) - xL * yL - xH * yH in R8-R10,R20,R15-R19
|
||||
// Store lower half in z, that's done
|
||||
SUBS R21, R8
|
||||
SBCS R22, R9
|
||||
STP (R8, R9), 32(R2)
|
||||
SBCS R23, R10
|
||||
SBCS R24, R20
|
||||
STP (R10, R20), 48(R2)
|
||||
SBCS R25, R15
|
||||
SBCS R26, R16
|
||||
SBCS R27, R17
|
||||
SBCS R29, R19
|
||||
SBC ZR, R7
|
||||
|
||||
// (xH * yH) * 2^512 + ((xH + xL) * (yH + yL) - xL * yL - xH * yH) * 2^256 + xL * yL
|
||||
// Store remaining limbs in z
|
||||
ADDS $1, R1
|
||||
ADCS R21, R15
|
||||
ADCS R22, R16
|
||||
STP (R15, R16), 64(R2)
|
||||
ADCS R23, R17
|
||||
ADCS R24, R19
|
||||
STP (R17, R19), 80(R2)
|
||||
ADCS R7, R25
|
||||
ADCS ZR, R26
|
||||
STP (R25, R26), 96(R2)
|
||||
ADCS ZR, R27
|
||||
ADC ZR, R29
|
||||
STP (R27, R29), 112(R2)
|
||||
|
||||
RET
|
||||
|
||||
// Expects that X0*Y0 is already in Z0(low),Z3(high) and X0*Y1 in Z1(low),Z2(high)
|
||||
// Z0 is not actually touched
|
||||
// Result of (X0-X1) * (Y0-Y3) will be in Z0-Z5
|
||||
// Inputs remain intact
|
||||
#define mul128x256comba(X0, X1, Y0, Y1, Y2, Y3, Z0, Z1, Z2, Z3, Z4, Z5, T0, T1, T2, T3)\
|
||||
MUL X1, Y0, T0 \
|
||||
UMULH X1, Y0, T1 \
|
||||
ADDS Z3, Z1 \
|
||||
ADC ZR, Z2 \
|
||||
\
|
||||
MUL X0, Y2, T2 \
|
||||
UMULH X0, Y2, T3 \
|
||||
ADDS T0, Z1 \
|
||||
ADCS T1, Z2 \
|
||||
ADC ZR, ZR, Z3 \
|
||||
\
|
||||
MUL X1, Y1, T0 \
|
||||
UMULH X1, Y1, T1 \
|
||||
ADDS T2, Z2 \
|
||||
ADCS T3, Z3 \
|
||||
ADC ZR, ZR, Z4 \
|
||||
\
|
||||
MUL X0, Y3, T2 \
|
||||
UMULH X0, Y3, T3 \
|
||||
ADDS T0, Z2 \
|
||||
ADCS T1, Z3 \
|
||||
ADC ZR, Z4 \
|
||||
\
|
||||
MUL X1, Y2, T0 \
|
||||
UMULH X1, Y2, T1 \
|
||||
ADDS T2, Z3 \
|
||||
ADCS T3, Z4 \
|
||||
ADC ZR, ZR, Z5 \
|
||||
\
|
||||
MUL X1, Y3, T2 \
|
||||
UMULH X1, Y3, T3 \
|
||||
ADDS T0, Z3 \
|
||||
ADCS T1, Z4 \
|
||||
ADC ZR, Z5 \
|
||||
ADDS T2, Z4 \
|
||||
ADC T3, Z5
|
||||
|
||||
// This implements the shifted 2^(B*w) Montgomery reduction from
|
||||
// https://eprint.iacr.org/2016/986.pdf, section Section 3.2, with
|
||||
// B = 4, w = 64. Performance results were reported in
|
||||
// https://eprint.iacr.org/2018/700.pdf Section 6.
|
||||
TEXT ·fp503MontgomeryReduce(SB), NOSPLIT, $0-16
|
||||
MOVD x+8(FP), R0
|
||||
|
||||
// Load x0-x1
|
||||
LDP 0(R0), (R2, R3)
|
||||
|
||||
// Load the prime constant in R25-R29
|
||||
LDP ·p503p1s8+32(SB), (R25, R26)
|
||||
LDP ·p503p1s8+48(SB), (R27, R29)
|
||||
|
||||
// [x0,x1] * p503p1s8 to R4-R9
|
||||
MUL R2, R25, R4 // x0 * p503p1s8[0]
|
||||
UMULH R2, R25, R7
|
||||
MUL R2, R26, R5 // x0 * p503p1s8[1]
|
||||
UMULH R2, R26, R6
|
||||
|
||||
mul128x256comba(R2, R3, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13)
|
||||
|
||||
LDP 16(R0), (R3, R11) // x2
|
||||
LDP 32(R0), (R12, R13)
|
||||
LDP 48(R0), (R14, R15)
|
||||
|
||||
// Left-shift result in R4-R9 by 56 to R4-R10
|
||||
ORR R9>>8, ZR, R10
|
||||
LSL $56, R9
|
||||
ORR R8>>8, R9
|
||||
LSL $56, R8
|
||||
ORR R7>>8, R8
|
||||
LSL $56, R7
|
||||
ORR R6>>8, R7
|
||||
LSL $56, R6
|
||||
ORR R5>>8, R6
|
||||
LSL $56, R5
|
||||
ORR R4>>8, R5
|
||||
LSL $56, R4
|
||||
|
||||
ADDS R4, R11 // x3
|
||||
ADCS R5, R12 // x4
|
||||
ADCS R6, R13
|
||||
ADCS R7, R14
|
||||
ADCS R8, R15
|
||||
LDP 64(R0), (R16, R17)
|
||||
LDP 80(R0), (R19, R20)
|
||||
MUL R3, R25, R4 // x2 * p503p1s8[0]
|
||||
UMULH R3, R25, R7
|
||||
ADCS R9, R16
|
||||
ADCS R10, R17
|
||||
ADCS ZR, R19
|
||||
ADCS ZR, R20
|
||||
LDP 96(R0), (R21, R22)
|
||||
LDP 112(R0), (R23, R24)
|
||||
MUL R3, R26, R5 // x2 * p503p1s8[1]
|
||||
UMULH R3, R26, R6
|
||||
ADCS ZR, R21
|
||||
ADCS ZR, R22
|
||||
ADCS ZR, R23
|
||||
ADC ZR, R24
|
||||
|
||||
// [x2,x3] * p503p1s8 to R4-R9
|
||||
mul128x256comba(R3, R11, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
|
||||
|
||||
ORR R9>>8, ZR, R10
|
||||
LSL $56, R9
|
||||
ORR R8>>8, R9
|
||||
LSL $56, R8
|
||||
ORR R7>>8, R8
|
||||
LSL $56, R7
|
||||
ORR R6>>8, R7
|
||||
LSL $56, R6
|
||||
ORR R5>>8, R6
|
||||
LSL $56, R5
|
||||
ORR R4>>8, R5
|
||||
LSL $56, R4
|
||||
|
||||
ADDS R4, R13 // x5
|
||||
ADCS R5, R14 // x6
|
||||
ADCS R6, R15
|
||||
ADCS R7, R16
|
||||
MUL R12, R25, R4 // x4 * p503p1s8[0]
|
||||
UMULH R12, R25, R7
|
||||
ADCS R8, R17
|
||||
ADCS R9, R19
|
||||
ADCS R10, R20
|
||||
ADCS ZR, R21
|
||||
MUL R12, R26, R5 // x4 * p503p1s8[1]
|
||||
UMULH R12, R26, R6
|
||||
ADCS ZR, R22
|
||||
ADCS ZR, R23
|
||||
ADC ZR, R24
|
||||
|
||||
// [x4,x5] * p503p1s8 to R4-R9
|
||||
mul128x256comba(R12, R13, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
|
||||
|
||||
ORR R9>>8, ZR, R10
|
||||
LSL $56, R9
|
||||
ORR R8>>8, R9
|
||||
LSL $56, R8
|
||||
ORR R7>>8, R8
|
||||
LSL $56, R7
|
||||
ORR R6>>8, R7
|
||||
LSL $56, R6
|
||||
ORR R5>>8, R6
|
||||
LSL $56, R5
|
||||
ORR R4>>8, R5
|
||||
LSL $56, R4
|
||||
|
||||
ADDS R4, R15 // x7
|
||||
ADCS R5, R16 // x8
|
||||
ADCS R6, R17
|
||||
ADCS R7, R19
|
||||
MUL R14, R25, R4 // x6 * p503p1s8[0]
|
||||
UMULH R14, R25, R7
|
||||
ADCS R8, R20
|
||||
ADCS R9, R21
|
||||
ADCS R10, R22
|
||||
MUL R14, R26, R5 // x6 * p503p1s8[1]
|
||||
UMULH R14, R26, R6
|
||||
ADCS ZR, R23
|
||||
ADC ZR, R24
|
||||
|
||||
// [x6,x7] * p503p1s8 to R4-R9
|
||||
mul128x256comba(R14, R15, R25, R26, R27, R29, R4, R5, R6, R7, R8, R9, R10, R0, R1, R2)
|
||||
|
||||
ORR R9>>8, ZR, R10
|
||||
LSL $56, R9
|
||||
ORR R8>>8, R9
|
||||
LSL $56, R8
|
||||
ORR R7>>8, R8
|
||||
LSL $56, R7
|
||||
ORR R6>>8, R7
|
||||
LSL $56, R6
|
||||
ORR R5>>8, R6
|
||||
LSL $56, R5
|
||||
ORR R4>>8, R5
|
||||
LSL $56, R4
|
||||
|
||||
MOVD z+0(FP), R0
|
||||
ADDS R4, R17
|
||||
ADCS R5, R19
|
||||
STP (R16, R17), 0(R0) // Store final result to z
|
||||
ADCS R6, R20
|
||||
ADCS R7, R21
|
||||
STP (R19, R20), 16(R0)
|
||||
ADCS R8, R22
|
||||
ADCS R9, R23
|
||||
STP (R21, R22), 32(R0)
|
||||
ADC R10, R24
|
||||
STP (R23, R24), 48(R0)
|
||||
|
||||
RET
|
||||
|
||||
TEXT ·fp503StrongReduce(SB), NOSPLIT, $0-8
|
||||
MOVD x+0(FP), R0
|
||||
|
||||
// Keep x in R1-R8, p503 in R9-R14, subtract to R1-R8
|
||||
LDP ·p503+16(SB), (R9, R10)
|
||||
LDP 0(R0), (R1, R2)
|
||||
LDP 16(R0), (R3, R4)
|
||||
SUBS R9, R1
|
||||
SBCS R9, R2
|
||||
|
||||
LDP 32(R0), (R5, R6)
|
||||
LDP ·p503+32(SB), (R11, R12)
|
||||
SBCS R9, R3
|
||||
SBCS R10, R4
|
||||
|
||||
LDP 48(R0), (R7, R8)
|
||||
LDP ·p503+48(SB), (R13, R14)
|
||||
SBCS R11, R5
|
||||
SBCS R12, R6
|
||||
|
||||
SBCS R13, R7
|
||||
SBCS R14, R8
|
||||
SBC ZR, ZR, R15
|
||||
|
||||
// Mask with the borrow and add p503
|
||||
AND R15, R9
|
||||
AND R15, R10
|
||||
AND R15, R11
|
||||
AND R15, R12
|
||||
AND R15, R13
|
||||
AND R15, R14
|
||||
|
||||
ADDS R9, R1
|
||||
ADCS R9, R2
|
||||
STP (R1, R2), 0(R0)
|
||||
ADCS R9, R3
|
||||
ADCS R10, R4
|
||||
STP (R3, R4), 16(R0)
|
||||
ADCS R11, R5
|
||||
ADCS R12, R6
|
||||
STP (R5, R6), 32(R0)
|
||||
ADCS R13, R7
|
||||
ADCS R14, R8
|
||||
STP (R7, R8), 48(R0)
|
||||
|
||||
RET
|
||||
46
external/github.com/cloudflare/sidh/p503/arith_decl.go
vendored
Normal file
46
external/github.com/cloudflare/sidh/p503/arith_decl.go
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build amd64,!noasm arm64,!noasm
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
|
||||
// If choice is neither 0 nor 1 then behaviour is undefined.
|
||||
// This function executes in constant time.
|
||||
//go:noescape
|
||||
func fp503ConditionalSwap(x, y *FpElement, choice uint8)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
//go:noescape
|
||||
func fp503AddReduced(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
//go:noescape
|
||||
func fp503SubReduced(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp503AddLazy(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp503X2AddLazy(z, x, y *FpElementX2)
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp503X2SubLazy(z, x, y *FpElementX2)
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
//go:noescape
|
||||
func fp503StrongReduce(x *FpElement)
|
||||
|
||||
// Computes z = x * y.
|
||||
//go:noescape
|
||||
func fp503Mul(z *FpElementX2, x, y *FpElement)
|
||||
|
||||
// Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value
|
||||
// of x may be changed. z=x not allowed.
|
||||
//go:noescape
|
||||
func fp503MontgomeryReduce(z *FpElement, x *FpElementX2)
|
||||
197
external/github.com/cloudflare/sidh/p503/arith_generic.go
vendored
Normal file
197
external/github.com/cloudflare/sidh/p503/arith_generic.go
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// +build noasm !amd64,!arm64
|
||||
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith"
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
func fp503AddReduced(z, x, y *FpElement) {
|
||||
var carry uint64
|
||||
|
||||
// z=x+y % p503
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
|
||||
// z = z - p503x2
|
||||
carry = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Subc64(carry, z[i], p503x2[i])
|
||||
}
|
||||
|
||||
// if z<0 add p503x2 back
|
||||
mask := uint64(0 - carry)
|
||||
carry = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, z[i], p503x2[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
func fp503SubReduced(z, x, y *FpElement) {
|
||||
var borrow uint64
|
||||
|
||||
// z = z - p503x2
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], borrow = Subc64(borrow, x[i], y[i])
|
||||
}
|
||||
|
||||
// if z<0 add p503x2 back
|
||||
mask := uint64(0 - borrow)
|
||||
borrow = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], borrow = Addc64(borrow, z[i], p503x2[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Conditionally swaps bits in x and y in constant time.
|
||||
// mask indicates bits to be swapped (set bits are swapped)
|
||||
// For details see "Hackers Delight, 2.20"
|
||||
//
|
||||
// Implementation doesn't actually depend on a prime field.
|
||||
func fp503ConditionalSwap(x, y *FpElement, mask uint8) {
|
||||
var tmp, mask64 uint64
|
||||
|
||||
mask64 = 0 - uint64(mask)
|
||||
for i := 0; i < NumWords; i++ {
|
||||
tmp = mask64 & (x[i] ^ y[i])
|
||||
x[i] = tmp ^ x[i]
|
||||
y[i] = tmp ^ y[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
|
||||
// with R=2^512. Destroys the input value.
|
||||
func fp503MontgomeryReduce(z *FpElement, x *FpElementX2) {
|
||||
var carry, t, u, v uint64
|
||||
var uv Uint128
|
||||
var count int
|
||||
|
||||
count = 3 // number of 0 digits in the least significat part of p503 + 1
|
||||
|
||||
for i := 0; i < NumWords; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
if j < (i - count + 1) {
|
||||
uv = Mul64(z[j], p503p1[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = Addc64(0, v, x[i])
|
||||
u, carry = Addc64(carry, u, 0)
|
||||
t += carry
|
||||
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := NumWords; i < 2*NumWords-1; i++ {
|
||||
if count > 0 {
|
||||
count--
|
||||
}
|
||||
for j := i - NumWords + 1; j < NumWords; j++ {
|
||||
if j < (NumWords - count) {
|
||||
uv = Mul64(z[j], p503p1[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = Addc64(0, v, x[i])
|
||||
u, carry = Addc64(carry, u, 0)
|
||||
|
||||
t += carry
|
||||
z[i-NumWords] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
v, carry = Addc64(0, v, x[2*NumWords-1])
|
||||
z[NumWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x * y.
|
||||
func fp503Mul(z *FpElementX2, x, y *FpElement) {
|
||||
var u, v, t uint64
|
||||
var carry uint64
|
||||
var uv Uint128
|
||||
|
||||
for i := uint64(0); i < NumWords; i++ {
|
||||
for j := uint64(0); j <= i; j++ {
|
||||
uv = Mul64(x[j], y[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := NumWords; i < (2*NumWords)-1; i++ {
|
||||
for j := i - NumWords + 1; j < NumWords; j++ {
|
||||
uv = Mul64(x[j], y[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
z[2*NumWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func fp503AddLazy(z, x, y *FpElement) {
|
||||
var carry uint64
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func fp503X2AddLazy(z, x, y *FpElementX2) {
|
||||
var carry uint64
|
||||
for i := 0; i < 2*NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
func fp503StrongReduce(x *FpElement) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < NumWords; i++ {
|
||||
x[i], borrow = Subc64(borrow, x[i], p503[i])
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
x[i], borrow = Addc64(borrow, x[i], p503[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
func fp503X2SubLazy(z, x, y *FpElementX2) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < 2*NumWords; i++ {
|
||||
z[i], borrow = Subc64(borrow, x[i], y[i])
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := NumWords; i < 2*NumWords; i++ {
|
||||
z[i], borrow = Addc64(borrow, z[i], p503[i-NumWords]&mask)
|
||||
}
|
||||
}
|
||||
178
external/github.com/cloudflare/sidh/p503/consts.go
vendored
Normal file
178
external/github.com/cloudflare/sidh/p503/consts.go
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// SIDH public key byte size
|
||||
P503_PublicKeySize = 378
|
||||
// SIDH shared secret byte size.
|
||||
P503_SharedSecretSize = 126
|
||||
// Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1
|
||||
P503_SecretBitLenA = 250
|
||||
// Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1
|
||||
P503_SecretBitLenB = 252
|
||||
// Size of a compuatation strategy for 2-torsion group
|
||||
strategySizeA = 124
|
||||
// Size of a compuatation strategy for 3-torsion group
|
||||
strategySizeB = 158
|
||||
// ceil(503+7/8)
|
||||
P503_Bytelen = 63
|
||||
// Number of limbs for a field element
|
||||
NumWords = 8
|
||||
)
|
||||
|
||||
// CPU Capabilities. Those flags are referred by assembly code. According to
|
||||
// https://v2ray.com/core/external/github.com/golang/go/issues/28230, variables referred from the
|
||||
// assembly must be in the same package.
|
||||
// We declare them variables not constants in order to facilitate testing.
|
||||
var (
|
||||
// Signals support for MULX which is in BMI2
|
||||
HasBMI2 = cpu.X86.HasBMI2
|
||||
// Signals support for ADX and BMI2
|
||||
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||
)
|
||||
|
||||
// The x-coordinate of PA
|
||||
var P503_affine_PA = Fp2Element{
|
||||
A: FpElement{
|
||||
0xE7EF4AA786D855AF, 0xED5758F03EB34D3B, 0x09AE172535A86AA9, 0x237B9CC07D622723,
|
||||
0xE3A284CBA4E7932D, 0x27481D9176C5E63F, 0x6A323FF55C6E71BF, 0x002ECC31A6FB8773,
|
||||
},
|
||||
B: FpElement{
|
||||
0x64D02E4E90A620B8, 0xDAB8128537D4B9F1, 0x4BADF77B8A228F98, 0x0F5DBDF9D1FB7D1B,
|
||||
0xBEC4DB288E1A0DCC, 0xE76A8665E80675DB, 0x6D6F252E12929463, 0x003188BD1463FACC,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of QA
|
||||
var P503_affine_QA = Fp2Element{
|
||||
A: FpElement{
|
||||
0xB79D41025DE85D56, 0x0B867DA9DF169686, 0x740E5368021C827D, 0x20615D72157BF25C,
|
||||
0xFF1590013C9B9F5B, 0xC884DCADE8C16CEA, 0xEBD05E53BF724E01, 0x0032FEF8FDA5748C,
|
||||
},
|
||||
B: FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of RA = PA-QA
|
||||
var P503_affine_RA = Fp2Element{
|
||||
A: FpElement{
|
||||
0x12E2E849AA0A8006, 0x41CF47008635A1E8, 0x9CD720A70798AED7, 0x42A820B42FCF04CF,
|
||||
0x7BF9BAD32AAE88B1, 0xF619127A54090BBE, 0x1CB10D8F56408EAA, 0x001D6B54C3C0EDEB,
|
||||
},
|
||||
B: FpElement{
|
||||
0x34DB54931CBAAC36, 0x420A18CB8DD5F0C4, 0x32008C1A48C0F44D, 0x3B3BA772B1CFD44D,
|
||||
0xA74B058FDAF13515, 0x095FC9CA7EEC17B4, 0x448E829D28F120F8, 0x00261EC3ED16A489,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of PB
|
||||
var P503_affine_PB = Fp2Element{
|
||||
A: FpElement{
|
||||
0x7EDE37F4FA0BC727, 0xF7F8EC5C8598941C, 0xD15519B516B5F5C8, 0xF6D5AC9B87A36282,
|
||||
0x7B19F105B30E952E, 0x13BD8B2025B4EBEE, 0x7B96D27F4EC579A2, 0x00140850CAB7E5DE,
|
||||
},
|
||||
B: FpElement{
|
||||
0x7764909DAE7B7B2D, 0x578ABB16284911AB, 0x76E2BFD146A6BF4D, 0x4824044B23AA02F0,
|
||||
0x1105048912A321F3, 0xB8A2E482CF0F10C1, 0x42FF7D0BE2152085, 0x0018E599C5223352,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of QB
|
||||
var P503_affine_QB = Fp2Element{
|
||||
A: FpElement{
|
||||
0x4256C520FB388820, 0x744FD7C3BAAF0A13, 0x4B6A2DDDB12CBCB8, 0xE46826E27F427DF8,
|
||||
0xFE4A663CD505A61B, 0xD6B3A1BAF025C695, 0x7C3BB62B8FCC00BD, 0x003AFDDE4A35746C,
|
||||
},
|
||||
B: FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of RB = PB - QB
|
||||
var P503_affine_RB = Fp2Element{
|
||||
A: FpElement{
|
||||
0x75601CD1E6C0DFCB, 0x1A9007239B58F93E, 0xC1F1BE80C62107AC, 0x7F513B898F29FF08,
|
||||
0xEA0BEDFF43E1F7B2, 0x2C6D94018CBAE6D0, 0x3A430D31BCD84672, 0x000D26892ECCFE83,
|
||||
},
|
||||
B: FpElement{
|
||||
0x1119D62AEA3007A1, 0xE3702AA4E04BAE1B, 0x9AB96F7D59F990E7, 0xF58440E8B43319C0,
|
||||
0xAF8134BEE1489775, 0xE7F7774E905192AA, 0xF54AE09308E98039, 0x001EF7A041A86112,
|
||||
},
|
||||
}
|
||||
|
||||
// 2-torsion group computation strategy
|
||||
var P503_AliceIsogenyStrategy = [strategySizeA]uint32{
|
||||
0x3D, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02,
|
||||
0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x1D, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01}
|
||||
|
||||
// 3-torsion group computation strategy
|
||||
var P503_BobIsogenyStrategy = [strategySizeB]uint32{
|
||||
0x47, 0x26, 0x15, 0x0D, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x05, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09,
|
||||
0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01,
|
||||
0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04,
|
||||
0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x08,
|
||||
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}
|
||||
|
||||
// Used internally by this package
|
||||
// -------------------------------
|
||||
|
||||
var p503 = FpElement{
|
||||
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xABFFFFFFFFFFFFFF,
|
||||
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
|
||||
}
|
||||
|
||||
// 2*503
|
||||
var p503x2 = FpElement{
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x57FFFFFFFFFFFFFF,
|
||||
0x2610B7B44423CF41, 0x3737ED90F6FCFB5E, 0xC08B8D7BB4EF49A0, 0x0080CDEA83023C3C,
|
||||
}
|
||||
|
||||
// p503 + 1
|
||||
var p503p1 = FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xAC00000000000000,
|
||||
0x13085BDA2211E7A0, 0x1B9BF6C87B7E7DAF, 0x6045C6BDDA77A4D0, 0x004066F541811E1E,
|
||||
}
|
||||
|
||||
// R^2=(2^512)^2 mod p
|
||||
var p503R2 = FpElement{
|
||||
0x5289A0CF641D011F, 0x9B88257189FED2B9, 0xA3B365D58DC8F17A, 0x5BC57AB6EFF168EC,
|
||||
0x9E51998BD84D4423, 0xBF8999CBAC3B5695, 0x46E9127BCE14CDB6, 0x003F6CFCE8B81771,
|
||||
}
|
||||
|
||||
// p503 + 1 left-shifted by 8, assuming little endianness
|
||||
var p503p1s8 = FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x085BDA2211E7A0AC, 0x9BF6C87B7E7DAF13, 0x45C6BDDA77A4D01B, 0x4066F541811E1E60,
|
||||
}
|
||||
|
||||
// 1*R mod p
|
||||
var P503_OneFp2 = Fp2Element{
|
||||
A: FpElement{
|
||||
0x00000000000003F9, 0x0000000000000000, 0x0000000000000000, 0xB400000000000000,
|
||||
0x63CB1A6EA6DED2B4, 0x51689D8D667EB37D, 0x8ACD77C71AB24142, 0x0026FBAEC60F5953},
|
||||
}
|
||||
|
||||
// 1/2 * R mod p
|
||||
var P503_HalfFp2 = Fp2Element{
|
||||
A: FpElement{
|
||||
0x00000000000001FC, 0x0000000000000000, 0x0000000000000000, 0xB000000000000000,
|
||||
0x3B69BB2464785D2A, 0x36824A2AF0FE9896, 0xF5899F427A94F309, 0x0033B15203C83BB8},
|
||||
}
|
||||
249
external/github.com/cloudflare/sidh/p503/field_ops.go
vendored
Normal file
249
external/github.com/cloudflare/sidh/p503/field_ops.go
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
package p503
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
type fp503Ops struct{}
|
||||
|
||||
func FieldOperations() FieldOps {
|
||||
return &fp503Ops{}
|
||||
}
|
||||
|
||||
func (fp503Ops) Add(dest, lhs, rhs *Fp2Element) {
|
||||
fp503AddReduced(&dest.A, &lhs.A, &rhs.A)
|
||||
fp503AddReduced(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func (fp503Ops) Sub(dest, lhs, rhs *Fp2Element) {
|
||||
fp503SubReduced(&dest.A, &lhs.A, &rhs.A)
|
||||
fp503SubReduced(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func (fp503Ops) Mul(dest, lhs, rhs *Fp2Element) {
|
||||
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
|
||||
a := &lhs.A
|
||||
b := &lhs.B
|
||||
c := &rhs.A
|
||||
d := &rhs.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
|
||||
//
|
||||
// Use Karatsuba's trick: note that
|
||||
//
|
||||
// (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
|
||||
//
|
||||
// so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
|
||||
|
||||
var ac, bd FpElementX2
|
||||
fp503Mul(&ac, a, c) // = a*c*R*R
|
||||
fp503Mul(&bd, b, d) // = b*d*R*R
|
||||
|
||||
var b_minus_a, c_minus_d FpElement
|
||||
fp503SubReduced(&b_minus_a, b, a) // = (b-a)*R
|
||||
fp503SubReduced(&c_minus_d, c, d) // = (c-d)*R
|
||||
|
||||
var ad_plus_bc FpElementX2
|
||||
fp503Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
|
||||
fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
|
||||
fp503X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
|
||||
|
||||
fp503MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
|
||||
|
||||
var ac_minus_bd FpElementX2
|
||||
fp503X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
|
||||
fp503MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
|
||||
}
|
||||
|
||||
// Set dest = 1/x
|
||||
//
|
||||
// Allowed to overlap dest with x.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (fp503Ops) Inv(dest, x *Fp2Element) {
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// 1 1 (a - bi) (a - bi)
|
||||
// -------- = -------- -------- = -----------
|
||||
// (a + bi) (a + bi) (a - bi) (a^2 + b^2)
|
||||
//
|
||||
// Letting c = 1/(a^2 + b^2), this is
|
||||
//
|
||||
// 1/(a+bi) = a*c - b*ci.
|
||||
|
||||
var asq_plus_bsq primeFieldElement
|
||||
var asq, bsq FpElementX2
|
||||
fp503Mul(&asq, a, a) // = a*a*R*R
|
||||
fp503Mul(&bsq, b, b) // = b*b*R*R
|
||||
fp503X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
|
||||
fp503MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p
|
||||
// Now asq_plus_bsq = a^2 + b^2
|
||||
|
||||
inv := asq_plus_bsq
|
||||
inv.Mul(&asq_plus_bsq, &asq_plus_bsq)
|
||||
inv.P34(&inv)
|
||||
inv.Mul(&inv, &inv)
|
||||
inv.Mul(&inv, &asq_plus_bsq)
|
||||
|
||||
var ac FpElementX2
|
||||
fp503Mul(&ac, a, &inv.A)
|
||||
fp503MontgomeryReduce(&dest.A, &ac)
|
||||
|
||||
var minus_b FpElement
|
||||
fp503SubReduced(&minus_b, &minus_b, b)
|
||||
var minus_bc FpElementX2
|
||||
fp503Mul(&minus_bc, &minus_b, &inv.A)
|
||||
fp503MontgomeryReduce(&dest.B, &minus_bc)
|
||||
}
|
||||
|
||||
func (fp503Ops) Square(dest, x *Fp2Element) {
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
|
||||
|
||||
var a2, a_plus_b, a_minus_b FpElement
|
||||
fp503AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
|
||||
fp503AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
|
||||
fp503SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
|
||||
|
||||
var asq_minus_bsq, ab2 FpElementX2
|
||||
fp503Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
|
||||
fp503Mul(&ab2, &a2, b) // = 2*a*b*R*R
|
||||
|
||||
fp503MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
|
||||
fp503MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p
|
||||
}
|
||||
|
||||
// In case choice == 1, performs following swap in constant time:
|
||||
// xPx <-> xQx
|
||||
// xPz <-> xQz
|
||||
// Otherwise returns xPx, xPz, xQx, xQz unchanged
|
||||
func (fp503Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) {
|
||||
fp503ConditionalSwap(&xPx.A, &xQx.A, choice)
|
||||
fp503ConditionalSwap(&xPx.B, &xQx.B, choice)
|
||||
fp503ConditionalSwap(&xPz.A, &xQz.A, choice)
|
||||
fp503ConditionalSwap(&xPz.B, &xQz.B, choice)
|
||||
}
|
||||
|
||||
// Converts values in x.A and x.B to Montgomery domain
|
||||
// x.A = x.A * R mod p
|
||||
// x.B = x.B * R mod p
|
||||
// Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B
|
||||
func (fp503Ops) ToMontgomery(x *Fp2Element) {
|
||||
var aRR FpElementX2
|
||||
|
||||
// convert to montgomery domain
|
||||
fp503Mul(&aRR, &x.A, &p503R2) // = a*R*R
|
||||
fp503MontgomeryReduce(&x.A, &aRR) // = a*R mod p
|
||||
fp503Mul(&aRR, &x.B, &p503R2)
|
||||
fp503MontgomeryReduce(&x.B, &aRR)
|
||||
}
|
||||
|
||||
// Converts values in x.A and x.B from Montgomery domain
|
||||
// a = x.A mod p
|
||||
// b = x.B mod p
|
||||
//
|
||||
// After returning from the call x is not modified.
|
||||
func (fp503Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) {
|
||||
var aR FpElementX2
|
||||
|
||||
// convert from montgomery domain
|
||||
// TODO: make fpXXXMontgomeryReduce use stack instead of reusing aR
|
||||
// so that we don't have do this copy here
|
||||
copy(aR[:], x.A[:])
|
||||
fp503MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p)
|
||||
fp503StrongReduce(&out.A) // = a mod p in [0, p)
|
||||
for i := range aR {
|
||||
aR[i] = 0
|
||||
}
|
||||
copy(aR[:], x.B[:])
|
||||
fp503MontgomeryReduce(&out.B, &aR)
|
||||
fp503StrongReduce(&out.B)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Prime Field
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Represents an element of the prime field F_p.
|
||||
type primeFieldElement struct {
|
||||
// This field element is in Montgomery form, so that the value `A` is
|
||||
// represented by `aR mod p`.
|
||||
A FpElement
|
||||
}
|
||||
|
||||
// Set dest = lhs * rhs.
|
||||
//
|
||||
// Allowed to overlap lhs or rhs with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement {
|
||||
a := &lhs.A // = a*R
|
||||
b := &rhs.A // = b*R
|
||||
|
||||
var ab FpElementX2
|
||||
fp503Mul(&ab, a, b) // = a*b*R*R
|
||||
fp503MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
|
||||
//
|
||||
// Allowed to overlap x with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement {
|
||||
dest.Mul(x, x)
|
||||
for i := uint8(1); i < k; i++ {
|
||||
dest.Mul(dest, dest)
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
|
||||
// Uses variation of sliding-window algorithm from with window size
|
||||
// of 5 and least to most significant bit sliding (left-to-right)
|
||||
// See HAC 14.85 for general description.
|
||||
//
|
||||
// Allowed to overlap x with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement {
|
||||
// Sliding-window strategy computed with etc/scripts/sliding_window_strat_calc.py
|
||||
//
|
||||
// This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
|
||||
// multiplications.
|
||||
powStrategy := []uint8{1, 12, 5, 5, 2, 7, 11, 3, 8, 4, 11, 4, 7, 5, 6, 3, 7, 5, 7, 2, 12, 5, 6, 4, 6, 8, 6, 4, 7, 5, 5, 8, 5, 8, 5, 5, 8, 9, 3, 6, 2, 10, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3}
|
||||
mulStrategy := []uint8{0, 12, 11, 10, 0, 1, 8, 3, 7, 1, 8, 3, 6, 7, 14, 2, 14, 14, 9, 0, 13, 9, 15, 5, 12, 7, 13, 7, 15, 6, 7, 9, 0, 5, 7, 6, 8, 8, 3, 7, 0, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3}
|
||||
|
||||
// Precompute lookup table of odd multiples of x for window
|
||||
// size k=5.
|
||||
lookup := [16]primeFieldElement{}
|
||||
xx := &primeFieldElement{}
|
||||
xx.Mul(x, x)
|
||||
lookup[0] = *x
|
||||
for i := 1; i < 16; i++ {
|
||||
lookup[i].Mul(&lookup[i-1], xx)
|
||||
}
|
||||
|
||||
// Now lookup = {x, x^3, x^5, ... }
|
||||
// so that lookup[i] = x^{2*i + 1}
|
||||
// so that lookup[k/2] = x^k, for odd k
|
||||
*dest = lookup[mulStrategy[0]]
|
||||
for i := uint8(1); i < uint8(len(powStrategy)); i++ {
|
||||
dest.Pow2k(dest, powStrategy[i])
|
||||
dest.Mul(dest, &lookup[mulStrategy[i]])
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
2620
external/github.com/cloudflare/sidh/p751/arith_amd64.s
vendored
Normal file
2620
external/github.com/cloudflare/sidh/p751/arith_amd64.s
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1520
external/github.com/cloudflare/sidh/p751/arith_arm64.s
vendored
Normal file
1520
external/github.com/cloudflare/sidh/p751/arith_arm64.s
vendored
Normal file
File diff suppressed because it is too large
Load Diff
46
external/github.com/cloudflare/sidh/p751/arith_decl.go
vendored
Normal file
46
external/github.com/cloudflare/sidh/p751/arith_decl.go
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build amd64,!noasm arm64,!noasm
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
// If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x.
|
||||
// If choice is neither 0 nor 1 then behaviour is undefined.
|
||||
// This function executes in constant time.
|
||||
//go:noescape
|
||||
func fp751ConditionalSwap(x, y *FpElement, choice uint8)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
//go:noescape
|
||||
func fp751AddReduced(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
//go:noescape
|
||||
func fp751SubReduced(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp751AddLazy(z, x, y *FpElement)
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp751X2AddLazy(z, x, y *FpElementX2)
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
//go:noescape
|
||||
func fp751X2SubLazy(z, x, y *FpElementX2)
|
||||
|
||||
// Compute z = x * y.
|
||||
//go:noescape
|
||||
func fp751Mul(z *FpElementX2, x, y *FpElement)
|
||||
|
||||
// Compute Montgomery reduction: set z = x * R^{-1} (mod 2*p).
|
||||
// It may destroy the input value.
|
||||
//go:noescape
|
||||
func fp751MontgomeryReduce(z *FpElement, x *FpElementX2)
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
//go:noescape
|
||||
func fp751StrongReduce(x *FpElement)
|
||||
196
external/github.com/cloudflare/sidh/p751/arith_generic.go
vendored
Normal file
196
external/github.com/cloudflare/sidh/p751/arith_generic.go
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
// +build noasm !amd64,!arm64
|
||||
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/arith"
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
// Compute z = x + y (mod p).
|
||||
func fp751AddReduced(z, x, y *FpElement) {
|
||||
var carry uint64
|
||||
|
||||
// z=x+y % p751
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
|
||||
// z = z - p751x2
|
||||
carry = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Subc64(carry, z[i], p751x2[i])
|
||||
}
|
||||
|
||||
// z = z + p751x2
|
||||
mask := uint64(0 - carry)
|
||||
carry = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, z[i], p751x2[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y (mod p).
|
||||
func fp751SubReduced(z, x, y *FpElement) {
|
||||
var borrow uint64
|
||||
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], borrow = Subc64(borrow, x[i], y[i])
|
||||
}
|
||||
|
||||
mask := uint64(0 - borrow)
|
||||
borrow = 0
|
||||
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], borrow = Addc64(borrow, z[i], p751x2[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Conditionally swaps bits in x and y in constant time.
|
||||
// mask indicates bits to be swaped (set bits are swapped)
|
||||
// For details see "Hackers Delight, 2.20"
|
||||
//
|
||||
// Implementation doesn't actually depend on a prime field.
|
||||
func fp751ConditionalSwap(x, y *FpElement, mask uint8) {
|
||||
var tmp, mask64 uint64
|
||||
|
||||
mask64 = 0 - uint64(mask)
|
||||
for i := 0; i < len(x); i++ {
|
||||
tmp = mask64 & (x[i] ^ y[i])
|
||||
x[i] = tmp ^ x[i]
|
||||
y[i] = tmp ^ y[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
|
||||
// with R=2^768. Destroys the input value.
|
||||
func fp751MontgomeryReduce(z *FpElement, x *FpElementX2) {
|
||||
var carry, t, u, v uint64
|
||||
var uv Uint128
|
||||
var count int
|
||||
|
||||
count = 5 // number of 0 digits in the least significat part of p751 + 1
|
||||
|
||||
for i := 0; i < NumWords; i++ {
|
||||
for j := 0; j < i; j++ {
|
||||
if j < (i - count + 1) {
|
||||
uv = Mul64(z[j], p751p1[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = Addc64(0, v, x[i])
|
||||
u, carry = Addc64(carry, u, 0)
|
||||
t += carry
|
||||
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := NumWords; i < 2*NumWords-1; i++ {
|
||||
if count > 0 {
|
||||
count--
|
||||
}
|
||||
for j := i - NumWords + 1; j < NumWords; j++ {
|
||||
if j < (NumWords - count) {
|
||||
uv = Mul64(z[j], p751p1[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
}
|
||||
v, carry = Addc64(0, v, x[i])
|
||||
u, carry = Addc64(carry, u, 0)
|
||||
|
||||
t += carry
|
||||
z[i-NumWords] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
v, carry = Addc64(0, v, x[2*NumWords-1])
|
||||
z[NumWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x * y.
|
||||
func fp751Mul(z *FpElementX2, x, y *FpElement) {
|
||||
var u, v, t uint64
|
||||
var carry uint64
|
||||
var uv Uint128
|
||||
|
||||
for i := uint64(0); i < NumWords; i++ {
|
||||
for j := uint64(0); j <= i; j++ {
|
||||
uv = Mul64(x[j], y[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
|
||||
for i := NumWords; i < (2*NumWords)-1; i++ {
|
||||
for j := i - NumWords + 1; j < NumWords; j++ {
|
||||
uv = Mul64(x[j], y[i-j])
|
||||
v, carry = Addc64(0, uv.L, v)
|
||||
u, carry = Addc64(carry, uv.H, u)
|
||||
t += carry
|
||||
}
|
||||
z[i] = v
|
||||
v = u
|
||||
u = t
|
||||
t = 0
|
||||
}
|
||||
z[2*NumWords-1] = v
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func fp751AddLazy(z, x, y *FpElement) {
|
||||
var carry uint64
|
||||
for i := 0; i < NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x + y, without reducing mod p.
|
||||
func fp751X2AddLazy(z, x, y *FpElementX2) {
|
||||
var carry uint64
|
||||
for i := 0; i < 2*NumWords; i++ {
|
||||
z[i], carry = Addc64(carry, x[i], y[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce a field element in [0, 2*p) to one in [0,p).
|
||||
func fp751StrongReduce(x *FpElement) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < NumWords; i++ {
|
||||
x[i], borrow = Subc64(borrow, x[i], p751[i])
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := 0; i < NumWords; i++ {
|
||||
x[i], borrow = Addc64(borrow, x[i], p751[i]&mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute z = x - y, without reducing mod p.
|
||||
func fp751X2SubLazy(z, x, y *FpElementX2) {
|
||||
var borrow, mask uint64
|
||||
for i := 0; i < len(z); i++ {
|
||||
z[i], borrow = Subc64(borrow, x[i], y[i])
|
||||
}
|
||||
|
||||
// Sets all bits if borrow = 1
|
||||
mask = 0 - borrow
|
||||
borrow = 0
|
||||
for i := NumWords; i < len(z); i++ {
|
||||
z[i], borrow = Addc64(borrow, z[i], p751[i-NumWords]&mask)
|
||||
}
|
||||
}
|
||||
227
external/github.com/cloudflare/sidh/p751/consts.go
vendored
Normal file
227
external/github.com/cloudflare/sidh/p751/consts.go
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
package p751
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
cpu "v2ray.com/core/external/github.com/cloudflare/sidh/internal/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// SIDH public key byte size
|
||||
P751_PublicKeySize = 564
|
||||
// SIDH shared secret byte size.
|
||||
P751_SharedSecretSize = 188
|
||||
// Max size of secret key for 2-torsion group, corresponds to 2^e2
|
||||
P751_SecretBitLenA = 372
|
||||
// Size of secret key for 3-torsion group, corresponds to floor(log_2(3^e3))
|
||||
P751_SecretBitLenB = 378
|
||||
// P751 bytelen ceil(751/8)
|
||||
P751_Bytelen = 94
|
||||
// Size of a compuatation strategy for 2-torsion group
|
||||
strategySizeA = 185
|
||||
// Size of a compuatation strategy for 3-torsion group
|
||||
strategySizeB = 238
|
||||
// Number of 64-bit limbs used to store Fp element
|
||||
NumWords = 12
|
||||
)
|
||||
|
||||
// CPU Capabilities. Those flags are referred by assembly code. According to
|
||||
// https://v2ray.com/core/external/github.com/golang/go/issues/28230, variables referred from the
|
||||
// assembly must be in the same package.
|
||||
// We declare them variables not constants in order to facilitate testing.
|
||||
var (
|
||||
// Signals support for MULX which is in BMI2
|
||||
HasBMI2 = cpu.X86.HasBMI2
|
||||
// Signals support for ADX and BMI2
|
||||
HasADXandBMI2 = cpu.X86.HasBMI2 && cpu.X86.HasADX
|
||||
)
|
||||
|
||||
// The x-coordinate of PA
|
||||
var P751_affine_PA = Fp2Element{
|
||||
A: FpElement{
|
||||
0xC2FC08CEAB50AD8B, 0x1D7D710F55E457B1, 0xE8738D92953DCD6E,
|
||||
0xBAA7EBEE8A3418AA, 0xC9A288345F03F46F, 0xC8D18D167CFE2616,
|
||||
0x02043761F6B1C045, 0xAA1975E13180E7E9, 0x9E13D3FDC6690DE6,
|
||||
0x3A024640A3A3BB4F, 0x4E5AD44E6ACBBDAE, 0x0000544BEB561DAD,
|
||||
},
|
||||
B: FpElement{
|
||||
0xE6CC41D21582E411, 0x07C2ECB7C5DF400A, 0xE8E34B521432AEC4,
|
||||
0x50761E2AB085167D, 0x032CFBCAA6094B3C, 0x6C522F5FDF9DDD71,
|
||||
0x1319217DC3A1887D, 0xDC4FB25803353A86, 0x362C8D7B63A6AB09,
|
||||
0x39DCDFBCE47EA488, 0x4C27C99A2C28D409, 0x00003CB0075527C4,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of QA
|
||||
var P751_affine_QA = Fp2Element{
|
||||
A: FpElement{
|
||||
0xD56FE52627914862, 0x1FAD60DC96B5BAEA, 0x01E137D0BF07AB91,
|
||||
0x404D3E9252161964, 0x3C5385E4CD09A337, 0x4476426769E4AF73,
|
||||
0x9790C6DB989DFE33, 0xE06E1C04D2AA8B5E, 0x38C08185EDEA73B9,
|
||||
0xAA41F678A4396CA6, 0x92B9259B2229E9A0, 0x00002F9326818BE0,
|
||||
},
|
||||
B: FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of RA = PA-QA
|
||||
var P751_affine_RA = Fp2Element{
|
||||
A: FpElement{
|
||||
0x0BB84441DFFD19B3, 0x84B4DEA99B48C18E, 0x692DE648AD313805,
|
||||
0xE6D72761B6DFAEE0, 0x223975C672C3058D, 0xA0FDE0C3CBA26FDC,
|
||||
0xA5326132A922A3CA, 0xCA5E7F5D5EA96FA4, 0x127C7EFE33FFA8C6,
|
||||
0x4749B1567E2A23C4, 0x2B7DF5B4AF413BFA, 0x0000656595B9623C,
|
||||
},
|
||||
B: FpElement{
|
||||
0xED78C17F1EC71BE8, 0xF824D6DF753859B1, 0x33A10839B2A8529F,
|
||||
0xFC03E9E25FDEA796, 0xC4708A8054DF1762, 0x4034F2EC034C6467,
|
||||
0xABFB70FBF06ECC79, 0xDABE96636EC108B7, 0x49CBCFB090605FD3,
|
||||
0x20B89711819A45A7, 0xFB8E1590B2B0F63E, 0x0000556A5F964AB2,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of PB
|
||||
var P751_affine_PB = Fp2Element{
|
||||
A: FpElement{
|
||||
0xCFB6D71EF867AB0B, 0x4A5FDD76E9A45C76, 0x38B1EE69194B1F03,
|
||||
0xF6E7B18A7761F3F0, 0xFCF01A486A52C84C, 0xCBE2F63F5AA75466,
|
||||
0x6487BCE837B5E4D6, 0x7747F5A8C622E9B8, 0x4CBFE1E4EE6AEBBA,
|
||||
0x8A8616A13FA91512, 0x53DB980E1579E0A5, 0x000058FEBFF3BE69,
|
||||
},
|
||||
B: FpElement{
|
||||
0xA492034E7C075CC3, 0x677BAF00B04AA430, 0x3AAE0C9A755C94C8,
|
||||
0x1DC4B064E9EBB08B, 0x3684EDD04E826C66, 0x9BAA6CB661F01B22,
|
||||
0x20285A00AD2EFE35, 0xDCE95ABD0497065F, 0x16C7FBB3778E3794,
|
||||
0x26B3AC29CEF25AAF, 0xFB3C28A31A30AC1D, 0x000046ED190624EE,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of QB
|
||||
var P751_affine_QB = Fp2Element{
|
||||
A: FpElement{
|
||||
0xF1A8C9ED7B96C4AB, 0x299429DA5178486E, 0xEF4926F20CD5C2F4,
|
||||
0x683B2E2858B4716A, 0xDDA2FBCC3CAC3EEB, 0xEC055F9F3A600460,
|
||||
0xD5A5A17A58C3848B, 0x4652D836F42EAED5, 0x2F2E71ED78B3A3B3,
|
||||
0xA771C057180ADD1D, 0xC780A5D2D835F512, 0x0000114EA3B55AC1,
|
||||
},
|
||||
B: FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
},
|
||||
}
|
||||
|
||||
// The x-coordinate of RB = PB - QB
|
||||
var P751_affine_RB = Fp2Element{
|
||||
A: FpElement{
|
||||
0x1C0D6733769D0F31, 0xF084C3086E2659D1, 0xE23D5DA27BCBD133,
|
||||
0xF38EC9A8D5864025, 0x6426DC781B3B645B, 0x4B24E8E3C9FB03EE,
|
||||
0x6432792F9D2CEA30, 0x7CC8E8B1AE76E857, 0x7F32BFB626BB8963,
|
||||
0xB9F05995B48D7B74, 0x4D71200A7D67E042, 0x0000228457AF0637,
|
||||
},
|
||||
B: FpElement{
|
||||
0x4AE37E7D8F72BD95, 0xDD2D504B3E993488, 0x5D14E7FA1ECB3C3E,
|
||||
0x127610CEB75D6350, 0x255B4B4CAC446B11, 0x9EA12336C1F70CAF,
|
||||
0x79FA68A2147BC2F8, 0x11E895CFDADBBC49, 0xE4B9D3C4D6356C18,
|
||||
0x44B25856A67F951C, 0x5851541F61308D0B, 0x00002FFD994F7E4C,
|
||||
},
|
||||
}
|
||||
|
||||
// 2-torsion group computation strategy
|
||||
var P751_AliceIsogenyStrategy = [strategySizeA]uint32{
|
||||
0x50, 0x30, 0x1B, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02,
|
||||
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01,
|
||||
0x01, 0x01, 0x01, 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02,
|
||||
0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x15,
|
||||
0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03,
|
||||
0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, 0x03, 0x02,
|
||||
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02,
|
||||
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x21, 0x14, 0x0C, 0x07,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01,
|
||||
0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x01, 0x08, 0x05, 0x03, 0x02, 0x01, 0x01,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01}
|
||||
|
||||
// 3-torsion group computation strategy
|
||||
var P751_BobIsogenyStrategy = [strategySizeB]uint32{
|
||||
0x70, 0x3F, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02,
|
||||
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01,
|
||||
0x01, 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x1F, 0x10, 0x08, 0x04, 0x02,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02,
|
||||
0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x08, 0x04,
|
||||
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
|
||||
0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x31, 0x1F, 0x10,
|
||||
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
|
||||
0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01,
|
||||
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x0F, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
|
||||
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x07, 0x04, 0x02, 0x01,
|
||||
0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
|
||||
0x15, 0x0C, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
|
||||
0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x05, 0x03, 0x02,
|
||||
0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05,
|
||||
0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
|
||||
0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01}
|
||||
|
||||
// Used internally by this package. Not consts as Go doesn't allow arrays to be consts
|
||||
// -------------------------------
|
||||
|
||||
// p751
|
||||
var p751 = FpElement{
|
||||
0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
|
||||
0xffffffffffffffff, 0xffffffffffffffff, 0xeeafffffffffffff,
|
||||
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
|
||||
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
|
||||
|
||||
// 2*p751
|
||||
var p751x2 = FpElement{
|
||||
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
|
||||
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xDD5FFFFFFFFFFFFF,
|
||||
0xC7D92D0A93F0F151, 0xB52B363427EF98ED, 0x109D30CFADD7D0ED,
|
||||
0x0AC56A08B964AE90, 0x1C25213F2F75B8CD, 0x0000DFCBAA83EE38}
|
||||
|
||||
// p751 + 1
|
||||
var p751p1 = FpElement{
|
||||
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0xeeb0000000000000,
|
||||
0xe3ec968549f878a8, 0xda959b1a13f7cc76, 0x084e9867d6ebe876,
|
||||
0x8562b5045cb25748, 0x0e12909f97badc66, 0x00006fe5d541f71c}
|
||||
|
||||
// R^2 = (2^768)^2 mod p
|
||||
var p751R2 = FpElement{
|
||||
2535603850726686808, 15780896088201250090, 6788776303855402382,
|
||||
17585428585582356230, 5274503137951975249, 2266259624764636289,
|
||||
11695651972693921304, 13072885652150159301, 4908312795585420432,
|
||||
6229583484603254826, 488927695601805643, 72213483953973}
|
||||
|
||||
// 1*R mod p
|
||||
var P751_OneFp2 = Fp2Element{
|
||||
A: FpElement{
|
||||
0x249ad, 0x0, 0x0, 0x0, 0x0, 0x8310000000000000, 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x2d5b24bce5e2},
|
||||
}
|
||||
|
||||
// 1/2 * R mod p
|
||||
var P751_HalfFp2 = Fp2Element{
|
||||
A: FpElement{
|
||||
0x00000000000124D6, 0x0000000000000000, 0x0000000000000000,
|
||||
0x0000000000000000, 0x0000000000000000, 0xB8E0000000000000,
|
||||
0x9C8A2434C0AA7287, 0xA206996CA9A378A3, 0x6876280D41A41B52,
|
||||
0xE903B49F175CE04F, 0x0F8511860666D227, 0x00004EA07CFF6E7F},
|
||||
}
|
||||
254
external/github.com/cloudflare/sidh/p751/field_ops.go
vendored
Normal file
254
external/github.com/cloudflare/sidh/p751/field_ops.go
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
package p751
|
||||
|
||||
import . "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
|
||||
// 2*p751
|
||||
var ()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementtaion of FieldOperations
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Implements FieldOps
|
||||
type fp751Ops struct{}
|
||||
|
||||
func FieldOperations() FieldOps {
|
||||
return &fp751Ops{}
|
||||
}
|
||||
|
||||
func (fp751Ops) Add(dest, lhs, rhs *Fp2Element) {
|
||||
fp751AddReduced(&dest.A, &lhs.A, &rhs.A)
|
||||
fp751AddReduced(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func (fp751Ops) Sub(dest, lhs, rhs *Fp2Element) {
|
||||
fp751SubReduced(&dest.A, &lhs.A, &rhs.A)
|
||||
fp751SubReduced(&dest.B, &lhs.B, &rhs.B)
|
||||
}
|
||||
|
||||
func (fp751Ops) Mul(dest, lhs, rhs *Fp2Element) {
|
||||
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
|
||||
a := &lhs.A
|
||||
b := &lhs.B
|
||||
c := &rhs.A
|
||||
d := &rhs.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
|
||||
//
|
||||
// Use Karatsuba's trick: note that
|
||||
//
|
||||
// (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
|
||||
//
|
||||
// so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
|
||||
|
||||
var ac, bd FpElementX2
|
||||
fp751Mul(&ac, a, c) // = a*c*R*R
|
||||
fp751Mul(&bd, b, d) // = b*d*R*R
|
||||
|
||||
var b_minus_a, c_minus_d FpElement
|
||||
fp751SubReduced(&b_minus_a, b, a) // = (b-a)*R
|
||||
fp751SubReduced(&c_minus_d, c, d) // = (c-d)*R
|
||||
|
||||
var ad_plus_bc FpElementX2
|
||||
fp751Mul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
|
||||
fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
|
||||
fp751X2AddLazy(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
|
||||
|
||||
fp751MontgomeryReduce(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
|
||||
|
||||
var ac_minus_bd FpElementX2
|
||||
fp751X2SubLazy(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
|
||||
fp751MontgomeryReduce(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
|
||||
}
|
||||
|
||||
func (fp751Ops) Square(dest, x *Fp2Element) {
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
|
||||
|
||||
var a2, a_plus_b, a_minus_b FpElement
|
||||
fp751AddReduced(&a2, a, a) // = a*R + a*R = 2*a*R
|
||||
fp751AddReduced(&a_plus_b, a, b) // = a*R + b*R = (a+b)*R
|
||||
fp751SubReduced(&a_minus_b, a, b) // = a*R - b*R = (a-b)*R
|
||||
|
||||
var asq_minus_bsq, ab2 FpElementX2
|
||||
fp751Mul(&asq_minus_bsq, &a_plus_b, &a_minus_b) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
|
||||
fp751Mul(&ab2, &a2, b) // = 2*a*b*R*R
|
||||
|
||||
fp751MontgomeryReduce(&dest.A, &asq_minus_bsq) // = (a^2 - b^2)*R mod p
|
||||
fp751MontgomeryReduce(&dest.B, &ab2) // = 2*a*b*R mod p
|
||||
}
|
||||
|
||||
// Set dest = 1/x
|
||||
//
|
||||
// Allowed to overlap dest with x.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (fp751Ops) Inv(dest, x *Fp2Element) {
|
||||
a := &x.A
|
||||
b := &x.B
|
||||
|
||||
// We want to compute
|
||||
//
|
||||
// 1 1 (a - bi) (a - bi)
|
||||
// -------- = -------- -------- = -----------
|
||||
// (a + bi) (a + bi) (a - bi) (a^2 + b^2)
|
||||
//
|
||||
// Letting c = 1/(a^2 + b^2), this is
|
||||
//
|
||||
// 1/(a+bi) = a*c - b*ci.
|
||||
|
||||
var asq_plus_bsq primeFieldElement
|
||||
var asq, bsq FpElementX2
|
||||
fp751Mul(&asq, a, a) // = a*a*R*R
|
||||
fp751Mul(&bsq, b, b) // = b*b*R*R
|
||||
fp751X2AddLazy(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
|
||||
fp751MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p
|
||||
// Now asq_plus_bsq = a^2 + b^2
|
||||
|
||||
// Invert asq_plus_bsq
|
||||
inv := asq_plus_bsq
|
||||
inv.Mul(&asq_plus_bsq, &asq_plus_bsq)
|
||||
inv.P34(&inv)
|
||||
inv.Mul(&inv, &inv)
|
||||
inv.Mul(&inv, &asq_plus_bsq)
|
||||
|
||||
var ac FpElementX2
|
||||
fp751Mul(&ac, a, &inv.A)
|
||||
fp751MontgomeryReduce(&dest.A, &ac)
|
||||
|
||||
var minus_b FpElement
|
||||
fp751SubReduced(&minus_b, &minus_b, b)
|
||||
var minus_bc FpElementX2
|
||||
fp751Mul(&minus_bc, &minus_b, &inv.A)
|
||||
fp751MontgomeryReduce(&dest.B, &minus_bc)
|
||||
}
|
||||
|
||||
// In case choice == 1, performs following swap in constant time:
|
||||
// xPx <-> xQx
|
||||
// xPz <-> xQz
|
||||
// Otherwise returns xPx, xPz, xQx, xQz unchanged
|
||||
func (fp751Ops) CondSwap(xPx, xPz, xQx, xQz *Fp2Element, choice uint8) {
|
||||
fp751ConditionalSwap(&xPx.A, &xQx.A, choice)
|
||||
fp751ConditionalSwap(&xPx.B, &xQx.B, choice)
|
||||
fp751ConditionalSwap(&xPz.A, &xQz.A, choice)
|
||||
fp751ConditionalSwap(&xPz.B, &xQz.B, choice)
|
||||
}
|
||||
|
||||
// Converts values in x.A and x.B to Montgomery domain
|
||||
// x.A = x.A * R mod p
|
||||
// x.B = x.B * R mod p
|
||||
func (fp751Ops) ToMontgomery(x *Fp2Element) {
|
||||
var aRR FpElementX2
|
||||
|
||||
// convert to montgomery domain
|
||||
fp751Mul(&aRR, &x.A, &p751R2) // = a*R*R
|
||||
fp751MontgomeryReduce(&x.A, &aRR) // = a*R mod p
|
||||
fp751Mul(&aRR, &x.B, &p751R2)
|
||||
fp751MontgomeryReduce(&x.B, &aRR)
|
||||
}
|
||||
|
||||
// Converts values in x.A and x.B from Montgomery domain
|
||||
// a = x.A mod p
|
||||
// b = x.B mod p
|
||||
//
|
||||
// After returning from the call x is not modified.
|
||||
func (fp751Ops) FromMontgomery(x *Fp2Element, out *Fp2Element) {
|
||||
var aR FpElementX2
|
||||
|
||||
// convert from montgomery domain
|
||||
copy(aR[:], x.A[:])
|
||||
fp751MontgomeryReduce(&out.A, &aR) // = a mod p in [0, 2p)
|
||||
fp751StrongReduce(&out.A) // = a mod p in [0, p)
|
||||
for i := range aR {
|
||||
aR[i] = 0
|
||||
}
|
||||
copy(aR[:], x.B[:])
|
||||
fp751MontgomeryReduce(&out.B, &aR)
|
||||
fp751StrongReduce(&out.B)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Prime Field
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Represents an element of the prime field F_p in Montgomery domain
|
||||
type primeFieldElement struct {
|
||||
// The value `A`is represented by `aR mod p`.
|
||||
A FpElement
|
||||
}
|
||||
|
||||
// Set dest = lhs * rhs.
|
||||
//
|
||||
// Allowed to overlap lhs or rhs with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) Mul(lhs, rhs *primeFieldElement) *primeFieldElement {
|
||||
a := &lhs.A // = a*R
|
||||
b := &rhs.A // = b*R
|
||||
|
||||
var ab FpElementX2
|
||||
fp751Mul(&ab, a, b) // = a*b*R*R
|
||||
fp751MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
|
||||
//
|
||||
// Allowed to overlap x with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) Pow2k(x *primeFieldElement, k uint8) *primeFieldElement {
|
||||
dest.Mul(x, x)
|
||||
for i := uint8(1); i < k; i++ {
|
||||
dest.Mul(dest, dest)
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
|
||||
//
|
||||
// Allowed to overlap x with dest.
|
||||
//
|
||||
// Returns dest to allow chaining operations.
|
||||
func (dest *primeFieldElement) P34(x *primeFieldElement) *primeFieldElement {
|
||||
// Sliding-window strategy computed with Sage, awk, sed, and tr.
|
||||
//
|
||||
// This performs sum(powStrategy) = 744 squarings and len(mulStrategy)
|
||||
// = 137 multiplications, in addition to 1 squaring and 15
|
||||
// multiplications to build a lookup table.
|
||||
//
|
||||
// In total this is 745 squarings, 152 multiplications. Since squaring
|
||||
// is not implemented for the prime field, this is 897 multiplications
|
||||
// in total.
|
||||
powStrategy := [137]uint8{5, 7, 6, 2, 10, 4, 6, 9, 8, 5, 9, 4, 7, 5, 5, 4, 8, 3, 9, 5, 5, 4, 10, 4, 6, 6, 6, 5, 8, 9, 3, 4, 9, 4, 5, 6, 6, 2, 9, 4, 5, 5, 5, 7, 7, 9, 4, 6, 4, 8, 5, 8, 6, 6, 2, 9, 7, 4, 8, 8, 8, 4, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2}
|
||||
mulStrategy := [137]uint8{31, 23, 21, 1, 31, 7, 7, 7, 9, 9, 19, 15, 23, 23, 11, 7, 25, 5, 21, 17, 11, 5, 17, 7, 11, 9, 23, 9, 1, 19, 5, 3, 25, 15, 11, 29, 31, 1, 29, 11, 13, 9, 11, 27, 13, 19, 15, 31, 3, 29, 23, 31, 25, 11, 1, 21, 19, 15, 15, 21, 29, 13, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 3}
|
||||
initialMul := uint8(27)
|
||||
|
||||
// Build a lookup table of odd multiples of x.
|
||||
lookup := [16]primeFieldElement{}
|
||||
xx := &primeFieldElement{}
|
||||
xx.Mul(x, x) // Set xx = x^2
|
||||
lookup[0] = *x
|
||||
for i := 1; i < 16; i++ {
|
||||
lookup[i].Mul(&lookup[i-1], xx)
|
||||
}
|
||||
// Now lookup = {x, x^3, x^5, ... }
|
||||
// so that lookup[i] = x^{2*i + 1}
|
||||
// so that lookup[k/2] = x^k, for odd k
|
||||
|
||||
*dest = lookup[initialMul/2]
|
||||
for i := uint8(0); i < 137; i++ {
|
||||
dest.Pow2k(dest, powStrategy[i])
|
||||
dest.Mul(dest, &lookup[mulStrategy[i]/2])
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
226
external/github.com/cloudflare/sidh/sidh/api.go
vendored
Normal file
226
external/github.com/cloudflare/sidh/sidh/api.go
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
package sidh
|
||||
|
||||
import (
|
||||
"errors"
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
"io"
|
||||
)
|
||||
|
||||
// I keep it bool in order to be able to apply logical NOT
|
||||
type KeyVariant uint
|
||||
|
||||
// Id's correspond to bitlength of the prime field characteristic
|
||||
// Currently FP_751 is the only one supported by this implementation
|
||||
const (
|
||||
FP_503 uint8 = iota
|
||||
FP_751
|
||||
FP_964
|
||||
maxPrimeFieldId
|
||||
)
|
||||
|
||||
const (
|
||||
// First 2 bits identify SIDH variant third bit indicates
|
||||
// wether key is a SIKE variant (set) or SIDH (not set)
|
||||
|
||||
// 001 - SIDH: corresponds to 2-torsion group
|
||||
KeyVariant_SIDH_A KeyVariant = 1 << 0
|
||||
// 010 - SIDH: corresponds to 3-torsion group
|
||||
KeyVariant_SIDH_B = 1 << 1
|
||||
// 110 - SIKE
|
||||
KeyVariant_SIKE = 1<<2 | KeyVariant_SIDH_B
|
||||
)
|
||||
|
||||
// Base type for public and private key. Used mainly to carry domain
|
||||
// parameters.
|
||||
type key struct {
|
||||
// Domain parameters of the algorithm to be used with a key
|
||||
params *SidhParams
|
||||
// Flag indicates wether corresponds to 2-, 3-torsion group or SIKE
|
||||
keyVariant KeyVariant
|
||||
}
|
||||
|
||||
// Defines operations on public key
|
||||
type PublicKey struct {
|
||||
key
|
||||
affine_xP Fp2Element
|
||||
affine_xQ Fp2Element
|
||||
affine_xQmP Fp2Element
|
||||
}
|
||||
|
||||
// Defines operations on private key
|
||||
type PrivateKey struct {
|
||||
key
|
||||
// Secret key
|
||||
Scalar []byte
|
||||
// Used only by KEM
|
||||
S []byte
|
||||
}
|
||||
|
||||
// Accessor to the domain parameters
|
||||
func (key *key) Params() *SidhParams {
|
||||
return key.params
|
||||
}
|
||||
|
||||
// Accessor to key variant
|
||||
func (key *key) Variant() KeyVariant {
|
||||
return key.keyVariant
|
||||
}
|
||||
|
||||
// NewPrivateKey initializes private key.
|
||||
// Usage of this function guarantees that the object is correctly initialized.
|
||||
func NewPrivateKey(id uint8, v KeyVariant) *PrivateKey {
|
||||
prv := &PrivateKey{key: key{params: Params(id), keyVariant: v}}
|
||||
if (v & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
|
||||
prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
|
||||
} else {
|
||||
prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
|
||||
}
|
||||
if v == KeyVariant_SIKE {
|
||||
prv.S = make([]byte, prv.params.MsgLen)
|
||||
}
|
||||
return prv
|
||||
}
|
||||
|
||||
// NewPublicKey initializes public key.
|
||||
// Usage of this function guarantees that the object is correctly initialized.
|
||||
func NewPublicKey(id uint8, v KeyVariant) *PublicKey {
|
||||
return &PublicKey{key: key{params: Params(id), keyVariant: v}}
|
||||
}
|
||||
|
||||
// Import clears content of the public key currently stored in the structure
|
||||
// and imports key stored in the byte string. Returns error in case byte string
|
||||
// size is wrong. Doesn't perform any validation.
|
||||
func (pub *PublicKey) Import(input []byte) error {
|
||||
if len(input) != pub.Size() {
|
||||
return errors.New("sidh: input to short")
|
||||
}
|
||||
op := CurveOperations{Params: pub.params}
|
||||
ssSz := pub.params.SharedSecretSize
|
||||
op.Fp2FromBytes(&pub.affine_xP, input[0:ssSz])
|
||||
op.Fp2FromBytes(&pub.affine_xQ, input[ssSz:2*ssSz])
|
||||
op.Fp2FromBytes(&pub.affine_xQmP, input[2*ssSz:3*ssSz])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exports currently stored key. In case structure hasn't been filled with key data
|
||||
// returned byte string is filled with zeros.
|
||||
func (pub *PublicKey) Export() []byte {
|
||||
output := make([]byte, pub.params.PublicKeySize)
|
||||
op := CurveOperations{Params: pub.params}
|
||||
ssSz := pub.params.SharedSecretSize
|
||||
op.Fp2ToBytes(output[0:ssSz], &pub.affine_xP)
|
||||
op.Fp2ToBytes(output[ssSz:2*ssSz], &pub.affine_xQ)
|
||||
op.Fp2ToBytes(output[2*ssSz:3*ssSz], &pub.affine_xQmP)
|
||||
return output
|
||||
}
|
||||
|
||||
// Size returns size of the public key in bytes
|
||||
func (pub *PublicKey) Size() int {
|
||||
return pub.params.PublicKeySize
|
||||
}
|
||||
|
||||
// Exports currently stored key. In case structure hasn't been filled with key data
|
||||
// returned byte string is filled with zeros.
|
||||
func (prv *PrivateKey) Export() []byte {
|
||||
ret := make([]byte, len(prv.Scalar)+len(prv.S))
|
||||
copy(ret, prv.S)
|
||||
copy(ret[len(prv.S):], prv.Scalar)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Size returns size of the private key in bytes
|
||||
func (prv *PrivateKey) Size() int {
|
||||
tmp := len(prv.Scalar)
|
||||
if prv.Variant() == KeyVariant_SIKE {
|
||||
tmp += int(prv.params.MsgLen)
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
||||
// Import clears content of the private key currently stored in the structure
|
||||
// and imports key from octet string. In case of SIKE, the random value 'S'
|
||||
// must be prepended to the value of actual private key (see SIKE spec for details).
|
||||
// Function doesn't import public key value to PrivateKey object.
|
||||
func (prv *PrivateKey) Import(input []byte) error {
|
||||
if len(input) != prv.Size() {
|
||||
return errors.New("sidh: input to short")
|
||||
}
|
||||
copy(prv.S, input[:len(prv.S)])
|
||||
copy(prv.Scalar, input[len(prv.S):])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generates random private key for SIDH or SIKE. Generated value is
|
||||
// formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1>
|
||||
// for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)),
|
||||
// for KeyVariant_B.
|
||||
//
|
||||
// Returns error in case user provided RNG fails.
|
||||
func (prv *PrivateKey) Generate(rand io.Reader) error {
|
||||
var err error
|
||||
var dp *DomainParams
|
||||
|
||||
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
|
||||
dp = &prv.params.A
|
||||
} else {
|
||||
dp = &prv.params.B
|
||||
}
|
||||
|
||||
if prv.keyVariant == KeyVariant_SIKE && err == nil {
|
||||
_, err = io.ReadFull(rand, prv.S)
|
||||
}
|
||||
|
||||
// Private key generation takes advantage of the fact that keyspace for secret
|
||||
// key is (0, 2^x - 1), for some possitivite value of 'x' (see SIKE, 1.3.8).
|
||||
// It means that all bytes in the secret key, but the last one, can take any
|
||||
// value between <0x00,0xFF>. Similarily for the last byte, but generation
|
||||
// needs to chop off some bits, to make sure generated value is an element of
|
||||
// a key-space.
|
||||
_, err = io.ReadFull(rand, prv.Scalar)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1
|
||||
// Make sure scalar is SecretBitLen long. SIKE spec says that key
|
||||
// space starts from 0, but I'm not confortable with having low
|
||||
// value scalars used for private keys. It is still secrure as per
|
||||
// table 5.1 in [SIKE].
|
||||
prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Generates public key.
|
||||
//
|
||||
// Constant time.
|
||||
func (prv *PrivateKey) GeneratePublicKey() *PublicKey {
|
||||
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
|
||||
return publicKeyGenA(prv)
|
||||
}
|
||||
return publicKeyGenB(prv)
|
||||
}
|
||||
|
||||
// Computes a shared secret which is a j-invariant. Function requires that pub has
|
||||
// different KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8),
|
||||
// where P is a prime defining finite field.
|
||||
//
|
||||
// It's important to notice that each keypair must not be used more than once
|
||||
// to calculate shared secret.
|
||||
//
|
||||
// Function may return error. This happens only in case provided input is invalid.
|
||||
// Constant time for properly initialized private and public key.
|
||||
func DeriveSecret(prv *PrivateKey, pub *PublicKey) ([]byte, error) {
|
||||
|
||||
if (pub == nil) || (prv == nil) {
|
||||
return nil, errors.New("sidh: invalid arguments")
|
||||
}
|
||||
|
||||
if (pub.keyVariant == prv.keyVariant) || (pub.params.Id != prv.params.Id) {
|
||||
return nil, errors.New("sidh: public and private are incompatbile")
|
||||
}
|
||||
|
||||
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
|
||||
return deriveSecretA(prv, pub), nil
|
||||
} else {
|
||||
return deriveSecretB(prv, pub), nil
|
||||
}
|
||||
}
|
||||
82
external/github.com/cloudflare/sidh/sidh/params.go
vendored
Normal file
82
external/github.com/cloudflare/sidh/sidh/params.go
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package sidh
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
p503 "v2ray.com/core/external/github.com/cloudflare/sidh/p503"
|
||||
p751 "v2ray.com/core/external/github.com/cloudflare/sidh/p751"
|
||||
)
|
||||
|
||||
// Keeps mapping: SIDH prime field ID to domain parameters
|
||||
var sidhParams = make(map[uint8]SidhParams)
|
||||
|
||||
// Params returns domain parameters corresponding to finite field and identified by
|
||||
// `id` provieded by the caller. Function panics in case `id` wasn't registered earlier.
|
||||
func Params(id uint8) *SidhParams {
|
||||
if val, ok := sidhParams[id]; ok {
|
||||
return &val
|
||||
}
|
||||
panic("sidh: SIDH Params ID unregistered")
|
||||
}
|
||||
|
||||
func init() {
|
||||
p503 := SidhParams{
|
||||
Id: FP_503,
|
||||
PublicKeySize: p503.P503_PublicKeySize,
|
||||
SharedSecretSize: p503.P503_SharedSecretSize,
|
||||
A: DomainParams{
|
||||
Affine_P: p503.P503_affine_PA,
|
||||
Affine_Q: p503.P503_affine_QA,
|
||||
Affine_R: p503.P503_affine_RA,
|
||||
SecretBitLen: p503.P503_SecretBitLenA,
|
||||
SecretByteLen: uint((p503.P503_SecretBitLenA + 7) / 8),
|
||||
IsogenyStrategy: p503.P503_AliceIsogenyStrategy[:],
|
||||
},
|
||||
B: DomainParams{
|
||||
Affine_P: p503.P503_affine_PB,
|
||||
Affine_Q: p503.P503_affine_QB,
|
||||
Affine_R: p503.P503_affine_RB,
|
||||
SecretBitLen: p503.P503_SecretBitLenB,
|
||||
SecretByteLen: uint((p503.P503_SecretBitLenB + 7) / 8),
|
||||
IsogenyStrategy: p503.P503_BobIsogenyStrategy[:],
|
||||
},
|
||||
OneFp2: p503.P503_OneFp2,
|
||||
HalfFp2: p503.P503_HalfFp2,
|
||||
MsgLen: 24,
|
||||
// SIKEp751 provides 128 bit of classical security ([SIKE], 5.1)
|
||||
KemSize: 16,
|
||||
Bytelen: p503.P503_Bytelen,
|
||||
Op: p503.FieldOperations(),
|
||||
}
|
||||
|
||||
p751 := SidhParams{
|
||||
Id: FP_751,
|
||||
PublicKeySize: p751.P751_PublicKeySize,
|
||||
SharedSecretSize: p751.P751_SharedSecretSize,
|
||||
A: DomainParams{
|
||||
Affine_P: p751.P751_affine_PA,
|
||||
Affine_Q: p751.P751_affine_QA,
|
||||
Affine_R: p751.P751_affine_RA,
|
||||
IsogenyStrategy: p751.P751_AliceIsogenyStrategy[:],
|
||||
SecretBitLen: p751.P751_SecretBitLenA,
|
||||
SecretByteLen: uint((p751.P751_SecretBitLenA + 7) / 8),
|
||||
},
|
||||
B: DomainParams{
|
||||
Affine_P: p751.P751_affine_PB,
|
||||
Affine_Q: p751.P751_affine_QB,
|
||||
Affine_R: p751.P751_affine_RB,
|
||||
IsogenyStrategy: p751.P751_BobIsogenyStrategy[:],
|
||||
SecretBitLen: p751.P751_SecretBitLenB,
|
||||
SecretByteLen: uint((p751.P751_SecretBitLenB + 7) / 8),
|
||||
},
|
||||
OneFp2: p751.P751_OneFp2,
|
||||
HalfFp2: p751.P751_HalfFp2,
|
||||
MsgLen: 32,
|
||||
// SIKEp751 provides 192 bit of classical security ([SIKE], 5.1)
|
||||
KemSize: 24,
|
||||
Bytelen: p751.P751_Bytelen,
|
||||
Op: p751.FieldOperations(),
|
||||
}
|
||||
|
||||
sidhParams[FP_503] = p503
|
||||
sidhParams[FP_751] = p751
|
||||
}
|
||||
302
external/github.com/cloudflare/sidh/sidh/sidh.go
vendored
Normal file
302
external/github.com/cloudflare/sidh/sidh/sidh.go
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
package sidh
|
||||
|
||||
import (
|
||||
. "v2ray.com/core/external/github.com/cloudflare/sidh/internal/isogeny"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is
|
||||
//
|
||||
|
||||
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
|
||||
// for public key generation.
|
||||
func traverseTreePublicKeyA(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sidx int
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
|
||||
cparam := op.CalcCurveParamsEquiv4(curve)
|
||||
phi := Newisogeny4(op.Params.Op)
|
||||
strat := pub.params.A.IsogenyStrategy
|
||||
stratSz := len(strat)
|
||||
|
||||
for j := 1; j <= stratSz; j++ {
|
||||
for i <= stratSz-j {
|
||||
points = append(points, *xR)
|
||||
indices = append(indices, i)
|
||||
|
||||
k := strat[sidx]
|
||||
sidx++
|
||||
op.Pow2k(xR, &cparam, 2*k)
|
||||
i += int(k)
|
||||
}
|
||||
|
||||
cparam = phi.GenerateCurve(xR)
|
||||
for k := 0; k < len(points); k++ {
|
||||
points[k] = phi.EvaluatePoint(&points[k])
|
||||
}
|
||||
|
||||
*phiP = phi.EvaluatePoint(phiP)
|
||||
*phiQ = phi.EvaluatePoint(phiQ)
|
||||
*phiR = phi.EvaluatePoint(phiR)
|
||||
|
||||
// pop xR from points
|
||||
*xR, points = points[len(points)-1], points[:len(points)-1]
|
||||
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Traverses isogeny tree in order to compute xR needed
|
||||
// for public key generation.
|
||||
func traverseTreeSharedKeyA(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sidx int
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
|
||||
cparam := op.CalcCurveParamsEquiv4(curve)
|
||||
phi := Newisogeny4(op.Params.Op)
|
||||
strat := pub.params.A.IsogenyStrategy
|
||||
stratSz := len(strat)
|
||||
|
||||
for j := 1; j <= stratSz; j++ {
|
||||
for i <= stratSz-j {
|
||||
points = append(points, *xR)
|
||||
indices = append(indices, i)
|
||||
|
||||
k := strat[sidx]
|
||||
sidx++
|
||||
op.Pow2k(xR, &cparam, 2*k)
|
||||
i += int(k)
|
||||
}
|
||||
|
||||
cparam = phi.GenerateCurve(xR)
|
||||
for k := 0; k < len(points); k++ {
|
||||
points[k] = phi.EvaluatePoint(&points[k])
|
||||
}
|
||||
|
||||
// pop xR from points
|
||||
*xR, points = points[len(points)-1], points[:len(points)-1]
|
||||
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
|
||||
// for public key generation.
|
||||
func traverseTreePublicKeyB(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sidx int
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
|
||||
cparam := op.CalcCurveParamsEquiv3(curve)
|
||||
phi := Newisogeny3(op.Params.Op)
|
||||
strat := pub.params.B.IsogenyStrategy
|
||||
stratSz := len(strat)
|
||||
|
||||
for j := 1; j <= stratSz; j++ {
|
||||
for i <= stratSz-j {
|
||||
points = append(points, *xR)
|
||||
indices = append(indices, i)
|
||||
|
||||
k := strat[sidx]
|
||||
sidx++
|
||||
op.Pow3k(xR, &cparam, k)
|
||||
i += int(k)
|
||||
}
|
||||
|
||||
cparam = phi.GenerateCurve(xR)
|
||||
for k := 0; k < len(points); k++ {
|
||||
points[k] = phi.EvaluatePoint(&points[k])
|
||||
}
|
||||
|
||||
*phiP = phi.EvaluatePoint(phiP)
|
||||
*phiQ = phi.EvaluatePoint(phiQ)
|
||||
*phiR = phi.EvaluatePoint(phiR)
|
||||
|
||||
// pop xR from points
|
||||
*xR, points = points[len(points)-1], points[:len(points)-1]
|
||||
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
|
||||
// for public key generation.
|
||||
func traverseTreeSharedKeyB(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
|
||||
var points = make([]ProjectivePoint, 0, 8)
|
||||
var indices = make([]int, 0, 8)
|
||||
var i, sidx int
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
|
||||
cparam := op.CalcCurveParamsEquiv3(curve)
|
||||
phi := Newisogeny3(op.Params.Op)
|
||||
strat := pub.params.B.IsogenyStrategy
|
||||
stratSz := len(strat)
|
||||
|
||||
for j := 1; j <= stratSz; j++ {
|
||||
for i <= stratSz-j {
|
||||
points = append(points, *xR)
|
||||
indices = append(indices, i)
|
||||
|
||||
k := strat[sidx]
|
||||
sidx++
|
||||
op.Pow3k(xR, &cparam, k)
|
||||
i += int(k)
|
||||
}
|
||||
|
||||
cparam = phi.GenerateCurve(xR)
|
||||
for k := 0; k < len(points); k++ {
|
||||
points[k] = phi.EvaluatePoint(&points[k])
|
||||
}
|
||||
|
||||
// pop xR from points
|
||||
*xR, points = points[len(points)-1], points[:len(points)-1]
|
||||
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a public key in the 2-torsion group
|
||||
func publicKeyGenA(prv *PrivateKey) (pub *PublicKey) {
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2Element
|
||||
var tmp ProjectiveCurveParameters
|
||||
|
||||
pub = NewPublicKey(prv.params.Id, KeyVariant_SIDH_A)
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
var phi = Newisogeny4(op.Params.Op)
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
|
||||
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
|
||||
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
|
||||
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
|
||||
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
|
||||
|
||||
// Find isogeny kernel
|
||||
tmp.C = pub.params.OneFp2
|
||||
xR = op.ScalarMul3Pt(&tmp, &xPA, &xQA, &xRA, prv.params.A.SecretBitLen, prv.Scalar)
|
||||
|
||||
// Reset params object and travers isogeny tree
|
||||
tmp.C = pub.params.OneFp2
|
||||
tmp.A.Zeroize()
|
||||
traverseTreePublicKeyA(&tmp, &xR, &xPB, &xQB, &xRB, pub)
|
||||
|
||||
// Secret isogeny
|
||||
phi.GenerateCurve(&xR)
|
||||
xPA = phi.EvaluatePoint(&xPB)
|
||||
xQA = phi.EvaluatePoint(&xQB)
|
||||
xRA = phi.EvaluatePoint(&xRB)
|
||||
op.Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
op.Params.Op.Mul(&pub.affine_xP, &xPA.X, &invZP)
|
||||
op.Params.Op.Mul(&pub.affine_xQ, &xQA.X, &invZQ)
|
||||
op.Params.Op.Mul(&pub.affine_xQmP, &xRA.X, &invZR)
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a public key in the 3-torsion group
|
||||
func publicKeyGenB(prv *PrivateKey) (pub *PublicKey) {
|
||||
var xPB, xQB, xRB, xR ProjectivePoint
|
||||
var xPA, xQA, xRA ProjectivePoint
|
||||
var invZP, invZQ, invZR Fp2Element
|
||||
var tmp ProjectiveCurveParameters
|
||||
|
||||
pub = NewPublicKey(prv.params.Id, prv.keyVariant)
|
||||
var op = CurveOperations{Params: pub.params}
|
||||
var phi = Newisogeny3(op.Params.Op)
|
||||
|
||||
// Load points for B
|
||||
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
|
||||
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
|
||||
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
|
||||
|
||||
// Load points for A
|
||||
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
|
||||
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
|
||||
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
|
||||
|
||||
tmp.C = pub.params.OneFp2
|
||||
xR = op.ScalarMul3Pt(&tmp, &xPB, &xQB, &xRB, prv.params.B.SecretBitLen, prv.Scalar)
|
||||
|
||||
tmp.C = pub.params.OneFp2
|
||||
tmp.A.Zeroize()
|
||||
traverseTreePublicKeyB(&tmp, &xR, &xPA, &xQA, &xRA, pub)
|
||||
|
||||
phi.GenerateCurve(&xR)
|
||||
xPB = phi.EvaluatePoint(&xPA)
|
||||
xQB = phi.EvaluatePoint(&xQA)
|
||||
xRB = phi.EvaluatePoint(&xRA)
|
||||
op.Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
|
||||
|
||||
op.Params.Op.Mul(&pub.affine_xP, &xPB.X, &invZP)
|
||||
op.Params.Op.Mul(&pub.affine_xQ, &xQB.X, &invZQ)
|
||||
op.Params.Op.Mul(&pub.affine_xQmP, &xRB.X, &invZR)
|
||||
return
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Key agreement functions
|
||||
//
|
||||
|
||||
// Establishing shared keys in in 2-torsion group
|
||||
func deriveSecretA(prv *PrivateKey, pub *PublicKey) []byte {
|
||||
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
|
||||
var cparam ProjectiveCurveParameters
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var op = CurveOperations{Params: prv.params}
|
||||
var phi = Newisogeny4(op.Params.Op)
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = pub.params.OneFp2
|
||||
op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
|
||||
xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.A.SecretBitLen, prv.Scalar)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyA(&cparam, &xR, pub)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
op.RecoverCurveCoefficients4(&cparam, &c)
|
||||
op.Jinvariant(&cparam, sharedSecret)
|
||||
return sharedSecret
|
||||
}
|
||||
|
||||
// Establishing shared keys in in 3-torsion group
|
||||
func deriveSecretB(prv *PrivateKey, pub *PublicKey) []byte {
|
||||
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
|
||||
var xP, xQ, xQmP ProjectivePoint
|
||||
var xR ProjectivePoint
|
||||
var cparam ProjectiveCurveParameters
|
||||
var op = CurveOperations{Params: prv.params}
|
||||
var phi = Newisogeny3(op.Params.Op)
|
||||
|
||||
// Recover curve coefficients
|
||||
cparam.C = pub.params.OneFp2
|
||||
op.RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
|
||||
|
||||
// Find kernel of the morphism
|
||||
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
|
||||
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
|
||||
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
|
||||
xR = op.ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.B.SecretBitLen, prv.Scalar)
|
||||
|
||||
// Traverse isogeny tree
|
||||
traverseTreeSharedKeyB(&cparam, &xR, pub)
|
||||
|
||||
// Calculate j-invariant on isogeneus curve
|
||||
c := phi.GenerateCurve(&xR)
|
||||
op.RecoverCurveCoefficients3(&cparam, &c)
|
||||
op.Jinvariant(&cparam, sharedSecret)
|
||||
return sharedSecret
|
||||
}
|
||||
Reference in New Issue
Block a user