mirror of https://github.com/cheat/cheat.git
139 lines
3.0 KiB
Go
139 lines
3.0 KiB
Go
package goldilocks
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"math/bits"
|
|
|
|
"github.com/cloudflare/circl/internal/conv"
|
|
"github.com/cloudflare/circl/math"
|
|
fp "github.com/cloudflare/circl/math/fp448"
|
|
)
|
|
|
|
// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogeneous to Goldilocks.
|
|
type twistCurve struct{}
|
|
|
|
// Identity returns the identity point.
|
|
func (twistCurve) Identity() *twistPoint {
|
|
return &twistPoint{
|
|
y: fp.One(),
|
|
z: fp.One(),
|
|
}
|
|
}
|
|
|
|
// subYDiv16 update x = (x - y) / 16.
|
|
func subYDiv16(x *scalar64, y int64) {
|
|
s := uint64(y >> 63)
|
|
x0, b0 := bits.Sub64((*x)[0], uint64(y), 0)
|
|
x1, b1 := bits.Sub64((*x)[1], s, b0)
|
|
x2, b2 := bits.Sub64((*x)[2], s, b1)
|
|
x3, b3 := bits.Sub64((*x)[3], s, b2)
|
|
x4, b4 := bits.Sub64((*x)[4], s, b3)
|
|
x5, b5 := bits.Sub64((*x)[5], s, b4)
|
|
x6, _ := bits.Sub64((*x)[6], s, b5)
|
|
x[0] = (x0 >> 4) | (x1 << 60)
|
|
x[1] = (x1 >> 4) | (x2 << 60)
|
|
x[2] = (x2 >> 4) | (x3 << 60)
|
|
x[3] = (x3 >> 4) | (x4 << 60)
|
|
x[4] = (x4 >> 4) | (x5 << 60)
|
|
x[5] = (x5 >> 4) | (x6 << 60)
|
|
x[6] = (x6 >> 4)
|
|
}
|
|
|
|
func recodeScalar(d *[113]int8, k *Scalar) {
|
|
var k64 scalar64
|
|
k64.fromScalar(k)
|
|
for i := 0; i < 112; i++ {
|
|
d[i] = int8((k64[0] & 0x1f) - 16)
|
|
subYDiv16(&k64, int64(d[i]))
|
|
}
|
|
d[112] = int8(k64[0])
|
|
}
|
|
|
|
// ScalarMult returns kP.
|
|
func (e twistCurve) ScalarMult(k *Scalar, P *twistPoint) *twistPoint {
|
|
var TabP [8]preTwistPointProy
|
|
var S preTwistPointProy
|
|
var d [113]int8
|
|
|
|
var isZero int
|
|
if k.IsZero() {
|
|
isZero = 1
|
|
}
|
|
subtle.ConstantTimeCopy(isZero, k[:], order[:])
|
|
|
|
minusK := *k
|
|
isEven := 1 - int(k[0]&0x1)
|
|
minusK.Neg()
|
|
subtle.ConstantTimeCopy(isEven, k[:], minusK[:])
|
|
recodeScalar(&d, k)
|
|
|
|
P.oddMultiples(TabP[:])
|
|
Q := e.Identity()
|
|
for i := 112; i >= 0; i-- {
|
|
Q.Double()
|
|
Q.Double()
|
|
Q.Double()
|
|
Q.Double()
|
|
mask := d[i] >> 7
|
|
absDi := (d[i] + mask) ^ mask
|
|
inx := int32((absDi - 1) >> 1)
|
|
sig := int((d[i] >> 7) & 0x1)
|
|
for j := range TabP {
|
|
S.cmov(&TabP[j], uint(subtle.ConstantTimeEq(inx, int32(j))))
|
|
}
|
|
S.cneg(sig)
|
|
Q.mixAdd(&S)
|
|
}
|
|
Q.cneg(uint(isEven))
|
|
return Q
|
|
}
|
|
|
|
const (
|
|
omegaFix = 7
|
|
omegaVar = 5
|
|
)
|
|
|
|
// CombinedMult returns mG+nP.
|
|
func (e twistCurve) CombinedMult(m, n *Scalar, P *twistPoint) *twistPoint {
|
|
nafFix := math.OmegaNAF(conv.BytesLe2BigInt(m[:]), omegaFix)
|
|
nafVar := math.OmegaNAF(conv.BytesLe2BigInt(n[:]), omegaVar)
|
|
|
|
if len(nafFix) > len(nafVar) {
|
|
nafVar = append(nafVar, make([]int32, len(nafFix)-len(nafVar))...)
|
|
} else if len(nafFix) < len(nafVar) {
|
|
nafFix = append(nafFix, make([]int32, len(nafVar)-len(nafFix))...)
|
|
}
|
|
|
|
var TabQ [1 << (omegaVar - 2)]preTwistPointProy
|
|
P.oddMultiples(TabQ[:])
|
|
Q := e.Identity()
|
|
for i := len(nafFix) - 1; i >= 0; i-- {
|
|
Q.Double()
|
|
// Generator point
|
|
if nafFix[i] != 0 {
|
|
idxM := absolute(nafFix[i]) >> 1
|
|
R := tabVerif[idxM]
|
|
if nafFix[i] < 0 {
|
|
R.neg()
|
|
}
|
|
Q.mixAddZ1(&R)
|
|
}
|
|
// Variable input point
|
|
if nafVar[i] != 0 {
|
|
idxN := absolute(nafVar[i]) >> 1
|
|
S := TabQ[idxN]
|
|
if nafVar[i] < 0 {
|
|
S.neg()
|
|
}
|
|
Q.mixAdd(&S)
|
|
}
|
|
}
|
|
return Q
|
|
}
|
|
|
|
// absolute returns always a positive value.
|
|
func absolute(x int32) int32 {
|
|
mask := x >> 31
|
|
return (x + mask) ^ mask
|
|
}
|