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") -}