@@ -227,6 +227,28 @@ func (lhs *ExtensionFieldElement) VartimeEq(rhs *ExtensionFieldElement) bool { | |||
return lhs.a.vartimeEq(rhs.a) && lhs.b.vartimeEq(rhs.b) | |||
} | |||
// Convert the input to wire format. | |||
// | |||
// The output byte slice must be at least 188 bytes long. | |||
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]) | |||
} | |||
// Read 188 bytes into the given ExtensionFieldElement. | |||
// | |||
// It is an error to call this function if the input byte slice is less than 188 bytes long. | |||
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]) | |||
} | |||
//------------------------------------------------------------------------------ | |||
// Prime Field | |||
//------------------------------------------------------------------------------ | |||
@@ -528,3 +550,49 @@ 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)) | |||
} | |||
} |
@@ -115,6 +115,38 @@ func (x ExtensionFieldElement) Generate(rand *rand.Rand, size int) reflect.Value | |||
// Extension Field | |||
//------------------------------------------------------------------------------ | |||
func TestOneExtensionFieldToBytes(t *testing.T) { | |||
var x ExtensionFieldElement | |||
var xBytes [188]byte | |||
x.One() | |||
x.ToBytes(xBytes[:]) | |||
if xBytes[0] != 1 { | |||
t.Error("Expected 1, got", xBytes[0]) | |||
} | |||
for i := 1; i < 188; i++ { | |||
if xBytes[i] != 0 { | |||
t.Error("Expected 0, got", xBytes[0]) | |||
} | |||
} | |||
} | |||
func TestExtensionFieldElementToBytesRoundTrip(t *testing.T) { | |||
roundTrips := func(x ExtensionFieldElement) bool { | |||
var xBytes [188]byte | |||
var xPrime ExtensionFieldElement | |||
x.ToBytes(xBytes[:]) | |||
xPrime.FromBytes(xBytes[:]) | |||
return x.VartimeEq(&xPrime) | |||
} | |||
if err := quick.Check(roundTrips, quickCheckConfig); err != nil { | |||
t.Error(err) | |||
} | |||
} | |||
func TestExtensionFieldElementMulDistributesOverAdd(t *testing.T) { | |||
mulDistributesOverAdd := func(x, y, z ExtensionFieldElement) bool { | |||
// Compute t1 = (x+y)*z | |||
@@ -50,12 +50,52 @@ type SIDHPublicKeyBob struct { | |||
affine_xQmP ExtensionFieldElement | |||
} | |||
// Read a public key from a byte slice. The input must be at least 564 bytes long. | |||
func (pubKey *SIDHPublicKeyBob) FromBytes(input []byte) { | |||
if len(input) < 564 { | |||
panic("Too short input to SIDH pubkey FromBytes, expected 564 bytes") | |||
} | |||
pubKey.affine_xP.FromBytes(input[0:188]) | |||
pubKey.affine_xQ.FromBytes(input[188:376]) | |||
pubKey.affine_xQmP.FromBytes(input[376:564]) | |||
} | |||
// Write a public key to a byte slice. The output must be at least 564 bytes long. | |||
func (pubKey *SIDHPublicKeyBob) ToBytes(output []byte) { | |||
if len(output) < 564 { | |||
panic("Too short output for SIDH pubkey FromBytes, expected 564 bytes") | |||
} | |||
pubKey.affine_xP.ToBytes(output[0:188]) | |||
pubKey.affine_xQ.ToBytes(output[188:376]) | |||
pubKey.affine_xQmP.ToBytes(output[376:564]) | |||
} | |||
type SIDHPublicKeyAlice struct { | |||
affine_xP ExtensionFieldElement | |||
affine_xQ ExtensionFieldElement | |||
affine_xQmP ExtensionFieldElement | |||
} | |||
// Read a public key from a byte slice. The input must be at least 564 bytes long. | |||
func (pubKey *SIDHPublicKeyAlice) FromBytes(input []byte) { | |||
if len(input) < 564 { | |||
panic("Too short input to SIDH pubkey FromBytes, expected 564 bytes") | |||
} | |||
pubKey.affine_xP.FromBytes(input[0:188]) | |||
pubKey.affine_xQ.FromBytes(input[188:376]) | |||
pubKey.affine_xQmP.FromBytes(input[376:564]) | |||
} | |||
// Write a public key to a byte slice. The output must be at least 564 bytes long. | |||
func (pubKey *SIDHPublicKeyAlice) ToBytes(output []byte) { | |||
if len(output) < 564 { | |||
panic("Too short output for SIDH pubkey FromBytes, expected 564 bytes") | |||
} | |||
pubKey.affine_xP.ToBytes(output[0:188]) | |||
pubKey.affine_xQ.ToBytes(output[188:376]) | |||
pubKey.affine_xQmP.ToBytes(output[376:564]) | |||
} | |||
type SIDHSecretKeyBob struct { | |||
scalar []uint8 | |||
} | |||