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.trials/prep_p503_trial4
@@ -236,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. | |||
@@ -247,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 | |||
} | |||
//------------------------------------------------------------------------------ | |||
@@ -372,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)) | |||
} | |||
} |
@@ -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") | |||
} |