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.trials/PERF
@@ -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)) | |||
} | |||
} |
@@ -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 | |||
@@ -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") | |||
} |