작성자 | SHA1 | 메시지 | 날짜 |
---|---|---|---|
Henry Case | 3ed0199d4f |
makes GeneratePublicKey method of PrivateKey
It makes a little bit more sense to have GeneratePublicKey as a method of PrivateKey. In this case code doesn't need to check if caller provided pointer is nil. Object was created by NewPrivateKey(), so it code can assume object was correctly initialized. The old GeneratePublicKey was returning an error when caller provided pointer was nil. As this possibility is now removed, method doesn't return error anymore. |
6 년 전 |
Henry Case | b4df092ecd |
cleanup: move from/to bytes conversion to single function
From/to bytes conversion is needed only in ExtensionFieldElement. Patch moves all conversion code to single place. Patch also removes some testing helpers which are no longer needed. |
6 년 전 |
Henry Case | 08f780b0f5 | Adds install target | 6 년 전 |
Kris Kwiatkowski | 3479e45558 | cleanup: removes PrimeFieldElement inversion | 6 년 전 |
Henry Case | 571611c9f7 | makefile: improvements | 6 년 전 |
Henry Case | 1c2c27017e |
cleanup: removes PrimeFieldElement::square method
The method is implemented in exactly same way as multiplication. Currently there is no explenation for it's existance. Benchmarking shows no change |
6 년 전 |
Henry Case | 0e6db56864 | cleanup: removes unused PrimeFieldElement methods | 6 년 전 |
Henry Case | 1336c8ff50 | cleanup: removes ProjectivePrimeFieldPoint | 6 년 전 |
@@ -8,6 +8,7 @@ matrix: | |||
fast_finish: true | |||
script: | |||
- make test | |||
- make bench | |||
- make cover | |||
- NOASM=1 make cover-sidh | |||
@@ -3,42 +3,58 @@ MK_FILE_PATH = $(lastword $(MAKEFILE_LIST)) | |||
PRJ_DIR = $(abspath $(dir $(MK_FILE_PATH))) | |||
GOPATH_LOCAL = $(PRJ_DIR)/build | |||
GOPATH_DIR = github.com/cloudflare/p751sidh | |||
CSHAKE_PKG = github.com/henrydcase/nobs/hash/sha3 | |||
CSHAKE_PKG ?= github.com/henrydcase/nobs/hash/sha3 | |||
TARGETS = p751toolbox sidh sike | |||
GOARCH ?= | |||
OPTS_GCCGO ?= -compiler gccgo -O2 -g | |||
OPTS_TAGS ?= -tags=noasm | |||
OPTS ?= | |||
OPTS_TAGS ?= -tags=noasm | |||
NOASM ?= | |||
# -run="NonExistent" is set to make sure tests are not run before benchmarking | |||
BENCH_OPTS ?= -bench=. -run="NonExistent" | |||
# whether to be verbose | |||
V ?= 1 | |||
ifeq ($(NOASM),1) | |||
OPTS+=$(OPTS_TAGS) | |||
endif | |||
ifeq ($(V),1) | |||
OPTS += -v # Be verbose | |||
OPTS += -gcflags=-m # Show results from inlining | |||
endif | |||
clean: | |||
rm -rf $(GOPATH_LOCAL) | |||
rm -rf coverage*.txt | |||
prep: | |||
build_env: | |||
GOPATH=$(GOPATH_LOCAL) go get $(CSHAKE_PKG) | |||
mkdir -p $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
cp -rf p751toolbox $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
cp -rf sidh $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
cp -rf sike $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
cp -rf etc $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
test-%: prep | |||
GOPATH=$(GOPATH_LOCAL) go test -v $(OPTS) $(GOPATH_DIR)/$* | |||
copy-target-%: | |||
cp -rf $* $(GOPATH_LOCAL)/src/$(GOPATH_DIR) | |||
prep_targets: build_env $(addprefix copy-target-, $(TARGETS)) | |||
install-%: prep_targets | |||
GOPATH=$(GOPATH_LOCAL) go install $(OPTS) $(GOPATH_DIR)/$* | |||
test-%: prep_targets | |||
GOPATH=$(GOPATH_LOCAL) go test $(OPTS) $(GOPATH_DIR)/$* | |||
bench-%: prep | |||
cd $*; GOPATH=$(GOPATH_LOCAL) go test -v $(OPTS) -bench=. | |||
bench-%: prep_targets | |||
cd $*; GOPATH=$(GOPATH_LOCAL) go test $(OPTS) $(BENCH_OPTS) | |||
cover-%: prep | |||
cover-%: prep_targets | |||
GOPATH=$(GOPATH_LOCAL) go test \ | |||
-race -coverprofile=coverage_$*.txt -covermode=atomic $(OPTS) $(GOPATH_DIR)/$* | |||
cat coverage_$*.txt >> coverage.txt | |||
rm coverage_$*.txt | |||
test: $(addprefix test-, $(TARGETS)) | |||
bench: $(addprefix bench-, $(TARGETS)) | |||
cover: $(addprefix cover-, $(TARGETS)) | |||
bench: $(addprefix bench-, $(TARGETS)) | |||
cover: $(addprefix cover-, $(TARGETS)) | |||
install: $(addprefix install-, $(TARGETS)) | |||
test: $(addprefix test-, $(TARGETS)) |
@@ -28,15 +28,6 @@ type ProjectivePoint struct { | |||
Z ExtensionFieldElement | |||
} | |||
// A point on the projective line P^1(F_p). | |||
// | |||
// This represents a point on the (Kummer line) of the prime-field subgroup of | |||
// the base curve E_0(F_p), defined by E_0 : y^2 = x^3 + x. | |||
type ProjectivePrimeFieldPoint struct { | |||
X PrimeFieldElement | |||
Z PrimeFieldElement | |||
} | |||
func (params *ProjectiveCurveParameters) FromAffine(a *ExtensionFieldElement) { | |||
params.A = *a | |||
params.C.One() | |||
@@ -158,34 +149,17 @@ func (cparams *ProjectiveCurveParameters) RecoverCurveCoefficients4(coefEq *Curv | |||
return | |||
} | |||
func (point *ProjectivePoint) FromAffinePrimeField(x *PrimeFieldElement) { | |||
point.X.A = x.A | |||
point.X.B = zeroExtensionField.B | |||
point.Z = oneExtensionField | |||
} | |||
func (point *ProjectivePoint) FromAffine(x *ExtensionFieldElement) { | |||
point.X = *x | |||
point.Z = oneExtensionField | |||
} | |||
func (point *ProjectivePrimeFieldPoint) FromAffine(x *PrimeFieldElement) { | |||
point.X = *x | |||
point.Z = onePrimeField | |||
} | |||
func (point *ProjectivePoint) ToAffine() *ExtensionFieldElement { | |||
affine_x := new(ExtensionFieldElement) | |||
affine_x.Inv(&point.Z).Mul(affine_x, &point.X) | |||
return affine_x | |||
} | |||
func (point *ProjectivePrimeFieldPoint) ToAffine() *PrimeFieldElement { | |||
affine_x := new(PrimeFieldElement) | |||
affine_x.Inv(&point.Z).Mul(affine_x, &point.X) | |||
return affine_x | |||
} | |||
func (lhs *ProjectivePoint) VartimeEq(rhs *ProjectivePoint) bool { | |||
var t0, t1 ExtensionFieldElement | |||
t0.Mul(&lhs.X, &rhs.Z) | |||
@@ -193,23 +167,11 @@ func (lhs *ProjectivePoint) VartimeEq(rhs *ProjectivePoint) bool { | |||
return t0.VartimeEq(&t1) | |||
} | |||
func (lhs *ProjectivePrimeFieldPoint) VartimeEq(rhs *ProjectivePrimeFieldPoint) bool { | |||
var t0, t1 PrimeFieldElement | |||
t0.Mul(&lhs.X, &rhs.Z) | |||
t1.Mul(&lhs.Z, &rhs.X) | |||
return t0.VartimeEq(&t1) | |||
} | |||
func ProjectivePointConditionalSwap(xP, xQ *ProjectivePoint, choice uint8) { | |||
ExtensionFieldConditionalSwap(&xP.X, &xQ.X, choice) | |||
ExtensionFieldConditionalSwap(&xP.Z, &xQ.Z, choice) | |||
} | |||
func ProjectivePrimeFieldPointConditionalSwap(xP, xQ *ProjectivePrimeFieldPoint, choice uint8) { | |||
PrimeFieldConditionalSwap(&xP.X, &xQ.X, choice) | |||
PrimeFieldConditionalSwap(&xP.Z, &xQ.Z, choice) | |||
} | |||
// 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 | |||
@@ -105,16 +105,6 @@ func (dest *ExtensionFieldElement) Mul(lhs, rhs *ExtensionFieldElement) *Extensi | |||
return dest | |||
} | |||
// Set dest = -x | |||
// | |||
// Allowed to overlap dest with x. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *ExtensionFieldElement) Neg(x *ExtensionFieldElement) *ExtensionFieldElement { | |||
dest.Sub(&zeroExtensionField, x) | |||
return dest | |||
} | |||
// Set dest = 1/x | |||
// | |||
// Allowed to overlap dest with x. | |||
@@ -142,18 +132,21 @@ func (dest *ExtensionFieldElement) Inv(x *ExtensionFieldElement) *ExtensionField | |||
fp751MontgomeryReduce(&asq_plus_bsq.A, &asq) // = (a^2 + b^2)*R mod p | |||
// Now asq_plus_bsq = a^2 + b^2 | |||
var asq_plus_bsq_inv PrimeFieldElement | |||
asq_plus_bsq_inv.Inv(&asq_plus_bsq) | |||
c := &asq_plus_bsq_inv.A | |||
// 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 fp751X2 | |||
fp751Mul(&ac, a, c) | |||
fp751Mul(&ac, a, &inv.A) | |||
fp751MontgomeryReduce(&dest.A, &ac) | |||
var minus_b Fp751Element | |||
fp751SubReduced(&minus_b, &minus_b, b) | |||
var minus_bc fp751X2 | |||
fp751Mul(&minus_bc, &minus_b, c) | |||
fp751Mul(&minus_bc, &minus_b, &inv.A) | |||
fp751MontgomeryReduce(&dest.B, &minus_bc) | |||
return dest | |||
@@ -243,8 +236,27 @@ func (x *ExtensionFieldElement) ToBytes(output []byte) { | |||
if len(output) < 188 { | |||
panic("output byte slice too short, need 188 bytes") | |||
} | |||
x.A.toBytesFromMontgomeryForm(output[0:94]) | |||
x.B.toBytesFromMontgomeryForm(output[94:188]) | |||
var a,b Fp751Element | |||
var aR fp751X2 | |||
// convert from montgomery domain | |||
copy(aR[:], x.A[:]) // = a*R | |||
fp751MontgomeryReduce(&a, &aR) // = a mod p in [0, 2p) | |||
fp751StrongReduce(&a) // = a mod p in [0, p) | |||
copy(aR[:], x.B[:]) | |||
fp751MontgomeryReduce(&b, &aR) | |||
fp751StrongReduce(&b) | |||
// convert to bytes in little endian form. 8*12 = 96, but we drop the last two bytes | |||
// since p is 751 < 752=94*8 bits. | |||
for i := 0; i < 94; i++ { | |||
// set i = j*8 + k | |||
j := i / 8 | |||
k := uint64(i % 8) | |||
output[i] = byte(a[j] >> (8 * k)) | |||
output[i+94] = byte(b[j] >> (8 * k)) | |||
} | |||
} | |||
// Read 188 bytes into the given ExtensionFieldElement. | |||
@@ -254,8 +266,20 @@ func (x *ExtensionFieldElement) FromBytes(input []byte) { | |||
if len(input) < 188 { | |||
panic("input byte slice too short, need 188 bytes") | |||
} | |||
x.A.montgomeryFormFromBytes(input[:94]) | |||
x.B.montgomeryFormFromBytes(input[94:188]) | |||
for i:=0; i<94; i++ { | |||
j := i / 8 | |||
k := uint64(i % 8) | |||
x.A[j] |= uint64(input[i]) << (8 * k) | |||
x.B[j] |= uint64(input[i+94]) << (8 * k) | |||
} | |||
// convert to montgomery domain | |||
var aRR fp751X2 | |||
fp751Mul(&aRR, &x.A, &montgomeryRsq) // = a*R*R | |||
fp751MontgomeryReduce(&x.A, &aRR) // = a*R mod p | |||
fp751Mul(&aRR, &x.B, &montgomeryRsq) // = a*R*R | |||
fp751MontgomeryReduce(&x.B, &aRR) // = a*R mod p | |||
} | |||
//------------------------------------------------------------------------------ | |||
@@ -277,35 +301,6 @@ var onePrimeField = PrimeFieldElement{ | |||
A: Fp751Element{0x249ad, 0x0, 0x0, 0x0, 0x0, 0x8310000000000000, 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x2d5b24bce5e2}, | |||
} | |||
// Set dest = 0. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Zero() *PrimeFieldElement { | |||
*dest = zeroPrimeField | |||
return dest | |||
} | |||
// Set dest = 1. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) One() *PrimeFieldElement { | |||
*dest = onePrimeField | |||
return dest | |||
} | |||
// Set dest to x. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) SetUint64(x uint64) *PrimeFieldElement { | |||
var xRR fp751X2 | |||
dest.A = Fp751Element{} // = 0 | |||
dest.A[0] = x // = x | |||
fp751Mul(&xRR, &dest.A, &montgomeryRsq) // = x*R*R | |||
fp751MontgomeryReduce(&dest.A, &xRR) // = x*R mod p | |||
return dest | |||
} | |||
// Set dest = lhs * rhs. | |||
// | |||
// Allowed to overlap lhs or rhs with dest. | |||
@@ -328,104 +323,14 @@ func (dest *PrimeFieldElement) Mul(lhs, rhs *PrimeFieldElement) *PrimeFieldEleme | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Pow2k(x *PrimeFieldElement, k uint8) *PrimeFieldElement { | |||
dest.Square(x) | |||
dest.Mul(x, x) | |||
for i := uint8(1); i < k; i++ { | |||
dest.Square(dest) | |||
dest.Mul(dest, dest) | |||
} | |||
return dest | |||
} | |||
// Set dest = x^2 | |||
// | |||
// Allowed to overlap x with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Square(x *PrimeFieldElement) *PrimeFieldElement { | |||
a := &x.A // = a*R | |||
b := &x.A // = b*R | |||
var ab fp751X2 | |||
fp751Mul(&ab, a, b) // = a*b*R*R | |||
fp751MontgomeryReduce(&dest.A, &ab) // = a*b*R mod p | |||
return dest | |||
} | |||
// Set dest = -x | |||
// | |||
// Allowed to overlap x with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Neg(x *PrimeFieldElement) *PrimeFieldElement { | |||
dest.Sub(&zeroPrimeField, x) | |||
return dest | |||
} | |||
// Set dest = lhs + rhs. | |||
// | |||
// Allowed to overlap lhs or rhs with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Add(lhs, rhs *PrimeFieldElement) *PrimeFieldElement { | |||
fp751AddReduced(&dest.A, &lhs.A, &rhs.A) | |||
return dest | |||
} | |||
// Set dest = lhs - rhs. | |||
// | |||
// Allowed to overlap lhs or rhs with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Sub(lhs, rhs *PrimeFieldElement) *PrimeFieldElement { | |||
fp751SubReduced(&dest.A, &lhs.A, &rhs.A) | |||
return dest | |||
} | |||
// Returns true if lhs = rhs. Takes variable time. | |||
func (lhs *PrimeFieldElement) VartimeEq(rhs *PrimeFieldElement) bool { | |||
return lhs.A.vartimeEq(rhs.A) | |||
} | |||
// If choice = 1u8, set (x,y) = (y,x). If choice = 0u8, set (x,y) = (x,y). | |||
// | |||
// Returns dest to allow chaining operations. | |||
func PrimeFieldConditionalSwap(x, y *PrimeFieldElement, choice uint8) { | |||
fp751ConditionalSwap(&x.A, &y.A, choice) | |||
} | |||
// Set dest = sqrt(x), if x is a square. If x is nonsquare dest is undefined. | |||
// | |||
// Allowed to overlap x with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Sqrt(x *PrimeFieldElement) *PrimeFieldElement { | |||
tmp_x := *x // Copy x in case dest == x | |||
// Since x is assumed to be square, x = y^2 | |||
dest.P34(x) // dest = (y^2)^((p-3)/4) = y^((p-3)/2) | |||
dest.Mul(dest, &tmp_x) // dest = y^2 * y^((p-3)/2) = y^((p+1)/2) | |||
// Now dest^2 = y^(p+1) = y^2 = x, so dest = sqrt(x) | |||
return dest | |||
} | |||
// Set dest = 1/x. | |||
// | |||
// Allowed to overlap x with dest. | |||
// | |||
// Returns dest to allow chaining operations. | |||
func (dest *PrimeFieldElement) Inv(x *PrimeFieldElement) *PrimeFieldElement { | |||
tmp_x := *x // Copy x in case dest == x | |||
dest.Square(x) // dest = x^2 | |||
dest.P34(dest) // dest = (x^2)^((p-3)/4) = x^((p-3)/2) | |||
dest.Square(dest) // dest = x^(p-3) | |||
dest.Mul(dest, &tmp_x) // dest = x^(p-2) | |||
return dest | |||
} | |||
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x). | |||
// | |||
// Allowed to overlap x with dest. | |||
@@ -448,7 +353,7 @@ func (dest *PrimeFieldElement) P34(x *PrimeFieldElement) *PrimeFieldElement { | |||
// Build a lookup table of odd multiples of x. | |||
lookup := [16]PrimeFieldElement{} | |||
xx := &PrimeFieldElement{} | |||
xx.Square(x) // Set xx = x^2 | |||
xx.Mul(x, x) // Set xx = x^2 | |||
lookup[0] = *x | |||
for i := 1; i < 16; i++ { | |||
lookup[i].Mul(&lookup[i-1], xx) | |||
@@ -498,49 +403,3 @@ func (x Fp751Element) vartimeEq(y Fp751Element) bool { | |||
return eq | |||
} | |||
// Read an Fp751Element from little-endian bytes and convert to Montgomery form. | |||
// | |||
// The input byte slice must be at least 94 bytes long. | |||
func (x *Fp751Element) montgomeryFormFromBytes(input []byte) { | |||
if len(input) < 94 { | |||
panic("input byte slice too short") | |||
} | |||
var a Fp751Element | |||
for i := 0; i < 94; i++ { | |||
// set i = j*8 + k | |||
j := i / 8 | |||
k := uint64(i % 8) | |||
a[j] |= uint64(input[i]) << (8 * k) | |||
} | |||
var aRR fp751X2 | |||
fp751Mul(&aRR, &a, &montgomeryRsq) // = a*R*R | |||
fp751MontgomeryReduce(x, &aRR) // = a*R mod p | |||
} | |||
// Given an Fp751Element in Montgomery form, convert to little-endian bytes. | |||
// | |||
// The output byte slice must be at least 94 bytes long. | |||
func (x *Fp751Element) toBytesFromMontgomeryForm(output []byte) { | |||
if len(output) < 94 { | |||
panic("output byte slice too short") | |||
} | |||
var a Fp751Element | |||
var aR fp751X2 | |||
copy(aR[:], x[:]) // = a*R | |||
fp751MontgomeryReduce(&a, &aR) // = a mod p in [0, 2p) | |||
fp751StrongReduce(&a) // = a mod p in [0, p) | |||
// 8*12 = 96, but we drop the last two bytes since p is 751 < 752=94*8 bits. | |||
for i := 0; i < 94; i++ { | |||
// set i = j*8 + k | |||
j := i / 8 | |||
k := uint64(i % 8) | |||
// Need parens because Go's operator precedence would interpret | |||
// a[j] >> 8*k as (a[j] >> 8) * k | |||
output[i] = byte(a[j] >> (8 * k)) | |||
} | |||
} |
@@ -35,9 +35,13 @@ func radix64ToBigInt(x []uint64) *big.Int { | |||
return val | |||
} | |||
func (x *PrimeFieldElement) toBigInt() *big.Int { | |||
func VartimeEq(x,y *PrimeFieldElement) bool { | |||
return x.A.vartimeEq(y.A) | |||
} | |||
func (x *Fp751Element) toBigInt() *big.Int { | |||
// Convert from Montgomery form | |||
return x.A.toBigIntFromMontgomeryForm() | |||
return x.toBigIntFromMontgomeryForm() | |||
} | |||
func (x *Fp751Element) toBigIntFromMontgomeryForm() *big.Int { | |||
@@ -64,8 +68,8 @@ func TestPrimeFieldElementToBigInt(t *testing.T) { | |||
// sage: assert(xR < 2*p) | |||
// sage: (xR / R) % p | |||
xBig, _ := new(big.Int).SetString("4469946751055876387821312289373600189787971305258234719850789711074696941114031433609871105823930699680637820852699269802003300352597419024286385747737509380032982821081644521634652750355306547718505685107272222083450567982240", 10) | |||
if xBig.Cmp(x.toBigInt()) != 0 { | |||
t.Error("Expected", xBig, "found", x.toBigInt()) | |||
if xBig.Cmp(x.A.toBigInt()) != 0 { | |||
t.Error("Expected", xBig, "found", x.A.toBigInt()) | |||
} | |||
} | |||
@@ -121,7 +125,6 @@ func TestOneExtensionFieldToBytes(t *testing.T) { | |||
x.One() | |||
x.ToBytes(xBytes[:]) | |||
if xBytes[0] != 1 { | |||
t.Error("Expected 1, got", xBytes[0]) | |||
} | |||
@@ -249,101 +252,16 @@ func TestExtensionFieldElementBatch3Inv(t *testing.T) { | |||
//------------------------------------------------------------------------------ | |||
// Prime Field | |||
//------------------------------------------------------------------------------ | |||
func TestPrimeFieldElementSetUint64VersusBigInt(t *testing.T) { | |||
setUint64RoundTrips := func(x uint64) bool { | |||
z := new(PrimeFieldElement).SetUint64(x).toBigInt().Uint64() | |||
return x == z | |||
} | |||
if err := quick.Check(setUint64RoundTrips, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestPrimeFieldElementAddVersusBigInt(t *testing.T) { | |||
addMatchesBigInt := func(x, y PrimeFieldElement) bool { | |||
z := new(PrimeFieldElement) | |||
z.Add(&x, &y) | |||
check := new(big.Int) | |||
check.Add(x.toBigInt(), y.toBigInt()) | |||
check.Mod(check, cln16prime) | |||
return check.Cmp(z.toBigInt()) == 0 | |||
} | |||
if err := quick.Check(addMatchesBigInt, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestPrimeFieldElementSubVersusBigInt(t *testing.T) { | |||
subMatchesBigInt := func(x, y PrimeFieldElement) bool { | |||
z := new(PrimeFieldElement) | |||
z.Sub(&x, &y) | |||
check := new(big.Int) | |||
check.Sub(x.toBigInt(), y.toBigInt()) | |||
check.Mod(check, cln16prime) | |||
return check.Cmp(z.toBigInt()) == 0 | |||
} | |||
if err := quick.Check(subMatchesBigInt, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestPrimeFieldElementInv(t *testing.T) { | |||
inverseIsCorrect := func(x PrimeFieldElement) bool { | |||
z := new(PrimeFieldElement) | |||
z.Inv(&x) | |||
// Now z = (1/x), so (z * x) * x == x | |||
z.Mul(z, &x).Mul(z, &x) | |||
return z.VartimeEq(&x) | |||
} | |||
// This is more expensive; run fewer tests | |||
var quickCheckConfig = &quick.Config{MaxCount: (1 << (8 + quickCheckScaleFactor))} | |||
if err := quick.Check(inverseIsCorrect, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestPrimeFieldElementSqrt(t *testing.T) { | |||
inverseIsCorrect := func(x PrimeFieldElement) bool { | |||
// Construct y = x^2 so we're sure y is square. | |||
y := new(PrimeFieldElement) | |||
y.Square(&x) | |||
z := new(PrimeFieldElement) | |||
z.Sqrt(y) | |||
// Now z = sqrt(y), so z^2 == y | |||
z.Square(z) | |||
return z.VartimeEq(y) | |||
} | |||
// This is more expensive; run fewer tests | |||
var quickCheckConfig = &quick.Config{MaxCount: (1 << (8 + quickCheckScaleFactor))} | |||
if err := quick.Check(inverseIsCorrect, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestPrimeFieldElementMulVersusBigInt(t *testing.T) { | |||
mulMatchesBigInt := func(x, y PrimeFieldElement) bool { | |||
z := new(PrimeFieldElement) | |||
z.Mul(&x, &y) | |||
check := new(big.Int) | |||
check.Mul(x.toBigInt(), y.toBigInt()) | |||
check.Mul(x.A.toBigInt(), y.A.toBigInt()) | |||
check.Mod(check, cln16prime) | |||
return check.Cmp(z.toBigInt()) == 0 | |||
return check.Cmp(z.A.toBigInt()) == 0 | |||
} | |||
if err := quick.Check(mulMatchesBigInt, quickCheckConfig); err != nil { | |||
@@ -357,10 +275,10 @@ func TestPrimeFieldElementP34VersusBigInt(t *testing.T) { | |||
z := new(PrimeFieldElement) | |||
z.P34(&x) | |||
check := x.toBigInt() | |||
check := x.A.toBigInt() | |||
check.Exp(check, p34, cln16prime) | |||
return check.Cmp(z.toBigInt()) == 0 | |||
return check.Cmp(z.A.toBigInt()) == 0 | |||
} | |||
// This is more expensive; run fewer tests | |||
@@ -370,26 +288,6 @@ func TestPrimeFieldElementP34VersusBigInt(t *testing.T) { | |||
} | |||
} | |||
func TestFp751ElementConditionalSwap(t *testing.T) { | |||
var one = Fp751Element{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} | |||
var two = Fp751Element{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2} | |||
var x = one | |||
var y = two | |||
fp751ConditionalSwap(&x, &y, 0) | |||
if !(x == one && y == two) { | |||
t.Error("Found", x, "expected", one) | |||
} | |||
fp751ConditionalSwap(&x, &y, 1) | |||
if !(x == two && y == one) { | |||
t.Error("Found", x, "expected", two) | |||
} | |||
} | |||
// Package-level storage for this field element is intended to deter | |||
// compiler optimizations. | |||
var benchmarkFp751Element Fp751Element | |||
@@ -452,51 +350,6 @@ func BenchmarkPrimeFieldElementMul(b *testing.B) { | |||
} | |||
} | |||
func BenchmarkPrimeFieldElementInv(b *testing.B) { | |||
z := &PrimeFieldElement{A: bench_x} | |||
w := new(PrimeFieldElement) | |||
for n := 0; n < b.N; n++ { | |||
w.Inv(z) | |||
} | |||
} | |||
func BenchmarkPrimeFieldElementSqrt(b *testing.B) { | |||
z := &PrimeFieldElement{A: bench_x} | |||
w := new(PrimeFieldElement) | |||
for n := 0; n < b.N; n++ { | |||
w.Sqrt(z) | |||
} | |||
} | |||
func BenchmarkPrimeFieldElementSquare(b *testing.B) { | |||
z := &PrimeFieldElement{A: bench_x} | |||
w := new(PrimeFieldElement) | |||
for n := 0; n < b.N; n++ { | |||
w.Square(z) | |||
} | |||
} | |||
func BenchmarkPrimeFieldElementAdd(b *testing.B) { | |||
z := &PrimeFieldElement{A: bench_x} | |||
w := new(PrimeFieldElement) | |||
for n := 0; n < b.N; n++ { | |||
w.Add(z, z) | |||
} | |||
} | |||
func BenchmarkPrimeFieldElementSub(b *testing.B) { | |||
z := &PrimeFieldElement{A: bench_x} | |||
w := new(PrimeFieldElement) | |||
for n := 0; n < b.N; n++ { | |||
w.Sub(z, z) | |||
} | |||
} | |||
// --- field operation functions | |||
func BenchmarkFp751Multiply(b *testing.B) { | |||
@@ -3,68 +3,17 @@ package p751toolbox | |||
// Tools used for testing and debugging | |||
import ( | |||
"bytes" | |||
"fmt" | |||
) | |||
func printHex(vector []byte) (out string) { | |||
var buffer bytes.Buffer | |||
buffer.WriteString("0x") | |||
len := len(vector) | |||
for i := len - 1; i >= 0; i-- { | |||
buffer.WriteString(fmt.Sprintf("%02x", vector[i])) | |||
} | |||
buffer.WriteString("\n") | |||
return buffer.String() | |||
} | |||
func (element Fp751Element) String() string { | |||
var out [94]byte | |||
element.toBytesFromMontgomeryForm(out[:]) | |||
return fmt.Sprintf("%s", printHex(out[:])) | |||
} | |||
func (primeElement PrimeFieldElement) String() string { | |||
return fmt.Sprintf("%s", primeElement.A.String()) | |||
return fmt.Sprintf("%X", primeElement.A.toBigInt().String()) | |||
} | |||
func (extElement ExtensionFieldElement) String() string { | |||
var out [188]byte | |||
extElement.ToBytes(out[:]) | |||
return fmt.Sprintf("A: %sB: %s", printHex(out[:94]), printHex(out[94:])) | |||
return fmt.Sprintf("\nA: %X\nB: %X", extElement.A.toBigInt().String(), extElement.B.toBigInt().String()) | |||
} | |||
func (point ProjectivePoint) String() string { | |||
return fmt.Sprintf("X:\n%sZ:\n%s", point.X.String(), point.Z.String()) | |||
} | |||
func (point ProjectivePrimeFieldPoint) String() string { | |||
return fmt.Sprintf("X:\n%sZ:\n%s", point.X.String(), point.Z.String()) | |||
} | |||
func (point Fp751Element) PrintHex() { | |||
fmt.Printf("\t") | |||
for i := 0; i < fp751NumWords/2; i++ { | |||
fmt.Printf("0x%0.16X, ", point[i]) | |||
} | |||
fmt.Printf("\n\t\t") | |||
for i := fp751NumWords / 2; i < fp751NumWords; i++ { | |||
fmt.Printf("0x%0.16X, ", point[i]) | |||
} | |||
fmt.Printf("\n") | |||
} | |||
func (extElement ExtensionFieldElement) PrintHex() { | |||
fmt.Printf("\t[r]: ") | |||
extElement.A.PrintHex() | |||
fmt.Printf("\t[u]: ") | |||
extElement.B.PrintHex() | |||
} | |||
func (point ProjectivePoint) PrintHex() { | |||
fmt.Printf("X:") | |||
point.X.PrintHex() | |||
fmt.Printf("Z:") | |||
point.X.PrintHex() | |||
fmt.Printf("\n") | |||
} |
@@ -164,19 +164,14 @@ func (prv *PrivateKey) Generate(rand io.Reader) error { | |||
return err | |||
} | |||
// Generates public key corresponding to prv. KeyVariant of generated public key | |||
// is same as PrivateKey. Fails only if prv was wrongly initialized. | |||
// Constant time for properly initialzied PrivateKey | |||
func GeneratePublicKey(prv *PrivateKey) (*PublicKey, error) { | |||
if prv == nil { | |||
return nil, errors.New("sidh: invalid arguments") | |||
} | |||
// Generates public key. | |||
// | |||
// Constant time. | |||
func (prv *PrivateKey) GeneratePublicKey() (*PublicKey) { | |||
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A { | |||
return publicKeyGenA(prv), nil | |||
} else { | |||
return publicKeyGenB(prv), nil | |||
return publicKeyGenA(prv) | |||
} | |||
return publicKeyGenB(prv) | |||
} | |||
// Computes a shared secret which is a j-invariant. Function requires that pub has | |||
@@ -93,10 +93,8 @@ func testKeygen(s *SidhParams, t *testing.T) { | |||
expPubA := convToPub(PkA, KeyVariant_SIDH_A) | |||
expPubB := convToPub(PkB, KeyVariant_SIDH_B) | |||
pubA, err := GeneratePublicKey(alicePrivate) | |||
checkErr(t, err, "public key A generation failed") | |||
pubB, err := GeneratePublicKey(bobPrivate) | |||
checkErr(t, err, "public key B generation failed") | |||
pubA := alicePrivate.GeneratePublicKey() | |||
pubB := bobPrivate.GeneratePublicKey() | |||
if !bytes.Equal(pubA.Export(), expPubA.Export()) { | |||
t.Fatalf("unexpected value of public key A") | |||
@@ -119,11 +117,8 @@ func testRoundtrip(s *SidhParams, t *testing.T) { | |||
checkErr(t, err, "key generation failed") | |||
// Generate public keys | |||
pubA, err := GeneratePublicKey(prvA) | |||
checkErr(t, err, "") | |||
pubB, err := GeneratePublicKey(prvB) | |||
checkErr(t, err, "") | |||
pubA := prvA.GeneratePublicKey() | |||
pubB := prvB.GeneratePublicKey() | |||
// Derive shared secret | |||
s1, err := DeriveSecret(prvB, pubA) | |||
@@ -317,7 +312,7 @@ func BenchmarkAliceKeyGenPub(b *testing.B) { | |||
prv := NewPrivateKey(params.Id, KeyVariant_SIDH_A) | |||
prv.Generate(rand.Reader) | |||
for n := 0; n < b.N; n++ { | |||
GeneratePublicKey(prv) | |||
prv.GeneratePublicKey() | |||
} | |||
} | |||
@@ -325,7 +320,7 @@ func BenchmarkBobKeyGenPub(b *testing.B) { | |||
prv := NewPrivateKey(params.Id, KeyVariant_SIDH_B) | |||
prv.Generate(rand.Reader) | |||
for n := 0; n < b.N; n++ { | |||
GeneratePublicKey(prv) | |||
prv.GeneratePublicKey() | |||
} | |||
} | |||
@@ -71,7 +71,7 @@ func Encrypt(rng io.Reader, pub *PublicKey, ptext []byte) ([]byte, error) { | |||
return nil, err | |||
} | |||
pkA, _ := GeneratePublicKey(skA) // Never fails | |||
pkA := skA.GeneratePublicKey() | |||
return encrypt(skA, pkA, pub, ptext) | |||
} | |||
@@ -152,7 +152,7 @@ func Encapsulate(rng io.Reader, pub *PublicKey) (ctext []byte, secret []byte, er | |||
return nil, nil, err | |||
} | |||
pkA, _ := GeneratePublicKey(skA) // Never fails | |||
pkA := skA.GeneratePublicKey() | |||
ctext, err = encrypt(skA, pkA, pub, ptext) | |||
if err != nil { | |||
return nil, nil, err | |||
@@ -197,7 +197,7 @@ func Decapsulate(prv *PrivateKey, pub *PublicKey, ctext []byte) ([]byte, error) | |||
skA.Import(r) | |||
// Never fails | |||
pkA, _ := GeneratePublicKey(skA) | |||
pkA := skA.GeneratePublicKey() | |||
c0 := pkA.Export() | |||
h = cshake.NewCShake256(nil, H) | |||
@@ -77,7 +77,7 @@ func TestPKEKeyGeneration(t *testing.T) { | |||
sk := NewPrivateKey(params.Id, KeyVariant_SIKE) | |||
err = sk.Generate(rand.Reader) | |||
checkErr(t, err, "PEK key generation") | |||
pk, _ := GeneratePublicKey(sk) | |||
pk := sk.GeneratePublicKey() | |||
// Try to encrypt | |||
ct, err := Encrypt(rand.Reader, pk, msg[:]) | |||
@@ -99,7 +99,7 @@ func TestNegativePKE(t *testing.T) { | |||
err = sk.Generate(rand.Reader) | |||
checkErr(t, err, "key generation") | |||
pk, _ := GeneratePublicKey(sk) | |||
pk := sk.GeneratePublicKey() | |||
ct, err := Encrypt(rand.Reader, pk, msg[:39]) | |||
if err == nil { | |||
@@ -152,7 +152,7 @@ func TestKEMKeyGeneration(t *testing.T) { | |||
// Generate key | |||
sk := NewPrivateKey(params.Id, KeyVariant_SIKE) | |||
checkErr(t, sk.Generate(rand.Reader), "error: key generation") | |||
pk, _ := GeneratePublicKey(sk) | |||
pk := sk.GeneratePublicKey() | |||
// calculated shared secret | |||
ct, ss_e, err := Encapsulate(rand.Reader, pk) | |||
@@ -168,7 +168,7 @@ func TestKEMKeyGeneration(t *testing.T) { | |||
func TestNegativeKEM(t *testing.T) { | |||
sk := NewPrivateKey(params.Id, KeyVariant_SIKE) | |||
checkErr(t, sk.Generate(rand.Reader), "error: key generation") | |||
pk, _ := GeneratePublicKey(sk) | |||
pk := sk.GeneratePublicKey() | |||
ct, ss_e, err := Encapsulate(rand.Reader, pk) | |||
checkErr(t, err, "pre-requisite for a test failed") | |||
@@ -201,7 +201,7 @@ func TestNegativeKEM(t *testing.T) { | |||
func TestNegativeKEMSameWrongResult(t *testing.T) { | |||
sk := NewPrivateKey(params.Id, KeyVariant_SIKE) | |||
checkErr(t, sk.Generate(rand.Reader), "error: key generation") | |||
pk, _ := GeneratePublicKey(sk) | |||
pk := sk.GeneratePublicKey() | |||
ct, encSs, err := Encapsulate(rand.Reader, pk) | |||
checkErr(t, err, "pre-requisite for a test failed") | |||
@@ -261,7 +261,7 @@ func testKeygen(pk, sk []byte) bool { | |||
} | |||
// Generate public key | |||
pubKey, _ := GeneratePublicKey(prvKey) | |||
pubKey := prvKey.GeneratePublicKey() | |||
return bytes.Equal(pubKey.Export(), pk) | |||
} | |||