From 1131231b8be1bfc65f006804ef3ef4983e193091 Mon Sep 17 00:00:00 2001 From: Kris Kwiatkowski Date: Sun, 2 Sep 2018 11:57:59 +0100 Subject: [PATCH] cleanup: moves from/to bytes conversion From/to bytes conversion will be refactored when p503 is introduced. Patch splits part that uses field specific functions from part that converts Fp element to bytes. Patch also removes some testing helpers which are no longer needed. --- p751toolbox/field.go | 107 ++++++++++++++++++++------------------ p751toolbox/field_test.go | 17 +++--- p751toolbox/print_test.go | 51 +----------------- 3 files changed, 67 insertions(+), 108 deletions(-) diff --git a/p751toolbox/field.go b/p751toolbox/field.go index 234d35e..40a4cc2 100644 --- a/p751toolbox/field.go +++ b/p751toolbox/field.go @@ -236,8 +236,20 @@ 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 + FromMontgomery(x, &a, &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. @@ -247,8 +259,49 @@ 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) + } + + ToMontgomery(x) +} + +// 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 ToMontgomery(x *ExtensionFieldElement) { + var aRR fp751X2 + + // convert to montgomery domain + fp751Mul(&aRR, &x.A, &montgomeryRsq) // = a*R*R + fp751MontgomeryReduce(&x.A, &aRR) // = a*R mod p + fp751Mul(&aRR, &x.B, &montgomeryRsq) + 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 FromMontgomery(x *ExtensionFieldElement, a,b *Fp751Element) { + var aR fp751X2 + + // convert from montgomery domain + copy(aR[:], x.A[:]) + fp751MontgomeryReduce(a, &aR) // = a mod p in [0, 2p) + fp751StrongReduce(a) // = a mod p in [0, p) + + for i:=range(aR) { + aR[i] = 0 + } + copy(aR[:], x.B[:]) + fp751MontgomeryReduce(b, &aR) + fp751StrongReduce(b) } //------------------------------------------------------------------------------ @@ -372,49 +425,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)) - } -} diff --git a/p751toolbox/field_test.go b/p751toolbox/field_test.go index edff4dc..250f197 100644 --- a/p751toolbox/field_test.go +++ b/p751toolbox/field_test.go @@ -39,9 +39,9 @@ func VartimeEq(x,y *PrimeFieldElement) bool { return x.A.vartimeEq(y.A) } -func (x *PrimeFieldElement) toBigInt() *big.Int { +func (x *Fp751Element) toBigInt() *big.Int { // Convert from Montgomery form - return x.A.toBigIntFromMontgomeryForm() + return x.toBigIntFromMontgomeryForm() } func (x *Fp751Element) toBigIntFromMontgomeryForm() *big.Int { @@ -68,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()) } } @@ -125,7 +125,6 @@ func TestOneExtensionFieldToBytes(t *testing.T) { x.One() x.ToBytes(xBytes[:]) - if xBytes[0] != 1 { t.Error("Expected 1, got", xBytes[0]) } @@ -259,10 +258,10 @@ func TestPrimeFieldElementMulVersusBigInt(t *testing.T) { 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 { @@ -276,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 diff --git a/p751toolbox/print_test.go b/p751toolbox/print_test.go index 8b565a8..04ba57b 100644 --- a/p751toolbox/print_test.go +++ b/p751toolbox/print_test.go @@ -3,64 +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 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") -}