Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hash to point from RFC9380 #510

Merged
merged 44 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d57adc8
Add skeleton
K1li4nL Apr 3, 2024
1bb3537
Add xerrors
K1li4nL Apr 4, 2024
9f759db
Add rfc9380 test vectors
K1li4nL Apr 12, 2024
767eb76
Add expand_message_xmd
K1li4nL Apr 12, 2024
18e2cb1
Add test vector sha512
K1li4nL Apr 15, 2024
2f1fea4
Add Elligator2 for curve25519
K1li4nL Apr 15, 2024
c515e67
Add mapToCurve for edwards25519
K1li4nL Apr 15, 2024
c383bb7
Fix type issues
K1li4nL Apr 15, 2024
a5d86d3
Add domain separator as param
K1li4nL Apr 15, 2024
362c938
Set to use sha512 by default
K1li4nL Apr 15, 2024
d852540
Extract repeated inputs in test
K1li4nL Apr 15, 2024
1668243
Add test
K1li4nL Apr 16, 2024
a5ff50c
Add helper
K1li4nL Apr 16, 2024
269b7d8
Use proper byte to fe
K1li4nL Apr 16, 2024
122d134
Use constant fe computed manually
K1li4nL Apr 16, 2024
7bfbe6a
Fix conversion
K1li4nL Apr 16, 2024
47f9900
Add test hashToField
K1li4nL Apr 16, 2024
63e4a25
Pad array
K1li4nL Apr 16, 2024
eddb1bb
Fix constants issues
K1li4nL Apr 21, 2024
9d958d6
Fix another constant
K1li4nL Apr 21, 2024
bf9943d
Add Hash() test
K1li4nL Apr 21, 2024
9c9071c
Fix typo
K1li4nL Apr 22, 2024
f926321
Rename tests to fit conventions
K1li4nL Apr 22, 2024
8955bfe
Add doc for new fe functions
K1li4nL May 6, 2024
629c640
Add inline operations comments
K1li4nL May 6, 2024
3822a69
Add rfc ref
K1li4nL May 6, 2024
6bad833
Add operation details
K1li4nL May 6, 2024
16af6b0
Fix links
K1li4nL May 6, 2024
c4ec0df
Add fe conversion test
K1li4nL May 11, 2024
e6a8437
Get rid of xerrors
K1li4nL May 11, 2024
1936f4e
Add long dst support + tests
K1li4nL May 11, 2024
83a0123
Add missing mod
K1li4nL May 11, 2024
b1f9626
Add expandMessageXOF
K1li4nL May 15, 2024
5aa4164
merging v4 changes
AnomalRoil Jun 6, 2024
47cfbc7
fixing few forgotten paths
AnomalRoil Jun 6, 2024
6610355
Add readme with code for test vector gen.
K1li4nL Jun 6, 2024
0d5ce34
Add test vector + more complex property test
K1li4nL Jun 6, 2024
09a1e77
Add ref to rfc
K1li4nL Jun 6, 2024
0149e2d
Force use of domain separator
K1li4nL Jun 6, 2024
1ae105a
Fix comment
K1li4nL Jun 6, 2024
465b0ca
Dedup variable
K1li4nL Jun 6, 2024
a607602
Add domainSep. check expand xof
K1li4nL Jun 6, 2024
cb99739
Fix rebase error
K1li4nL Jun 12, 2024
e44652d
Remove superfluous hash reset
K1li4nL Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions group/edwards25519/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
This implementation of ed25519 follows SUPERCOP ref10. The field elements are represented as follows:

`t[0] + t[1] * 2^26 + t[2] * 2^51 + t[3] * 2^77 + ... + t[9] * 2^230`

The test vectors to in `fe_test.go` were generated using this piece of code:

```
#!/usr/bin/env sage

import sage.all as sg

p = 2**255 -19
F = sg.GF(p)

base = [1, 2**26, 2**51, 2**77, 2**102, 2**128, 2**153, 2**179, 2**204, 2**230]
vectors = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
[1, -1, 1, -1, 1, -1, 1, -1, 1, -1],
[123312, 54,36467,64465,23524,235,234532,643,8975,74654],
[12323312, -54,356477,-69965,-23538, 32235, -233492,-643, 348975, 9174654],
]

for vect in vectors:
res = F(0)
i = 0
for elem in vect:
res += F(elem * base[i])
i += 1

print(res)
```

86 changes: 65 additions & 21 deletions group/edwards25519/fe.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package edwards25519

import (
"fmt"
"math/big"
)

// This code is a port of the public domain, "ref10" implementation of ed25519
Expand Down Expand Up @@ -135,27 +136,29 @@ func feFromBytes(dst *fieldElement, src []byte) {

// feToBytes marshals h to s.
// Preconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Write p=2^255-19; q=floor(h/p).
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
//
// Proof:
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
//
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
// Then 0<y<1.
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
//
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
// Then 0<y<1.
//
// Write r=h-pq.
// Have 0<=r<=p-1=2^255-20.
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
// Write r=h-pq.
// Have 0<=r<=p-1=2^255-20.
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
//
// Write x=r+19(2^-255)r+y.
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
// Write x=r+19(2^-255)r+y.
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
//
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
func feToBytes(s *[32]byte, h *fieldElement) {
var carry [10]int32

Expand Down Expand Up @@ -245,6 +248,38 @@ func feToBytes(s *[32]byte, h *fieldElement) {
s[31] = byte(h[9] >> 18)
}

// feToBn converts a fieldElement to a big.Int
// Limbs are individually stored in big endian but the array is in little endian, e.g:
// fe[0] corresponds to the smallest exponent, the array needs to be reversed for proper conversion to big.Int.
func feToBn(dst *big.Int, src *fieldElement) {
AnomalRoil marked this conversation as resolved.
Show resolved Hide resolved
var b [32]byte
feToBytes(&b, src)

half := len(b) / 2
l := len(b) - 1
for i := 0; i < half; i++ {
b[i], b[l-i] = b[l-i], b[i]
}

dst.SetBytes(b[:])
}

// feFromBn converts a big.Int to a fieldElement
// Limbs are individually stored in big endian but the array is in little endian, e.g:
// fe[0] corresponds to the smallest exponent, big.Int bytes need to be reversed for proper conversion.
func feFromBn(dst *fieldElement, src *big.Int) {
AnomalRoil marked this conversation as resolved.
Show resolved Hide resolved
bn := src.Mod(src, prime)
b := make([]byte, 32)
bn.FillBytes(b)
half := len(b) / 2
l := len(b) - 1
for i := 0; i < half; i++ {
b[i], b[l-i] = b[l-i], b[i]
}

feFromBytes(dst, b)
}

func feIsNegative(f *fieldElement) byte {
var s [32]byte
feToBytes(&s, f)
Expand All @@ -267,10 +302,12 @@ func feIsNonZero(f *fieldElement) int32 {
// feNeg sets h = -f
//
// Preconditions:
// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feNeg(h, f *fieldElement) {
for i := range h {
h[i] = -f[i]
Expand All @@ -281,11 +318,13 @@ func feNeg(h, f *fieldElement) {
// Can overlap h with f or g.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Notes on implementation strategy:
//
Expand Down Expand Up @@ -540,10 +579,12 @@ func feMul(h, f, g *fieldElement) {
// feSquare calculates h = f*f. Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feSquare(h, f *fieldElement) {
f0 := f[0]
f1 := f[1]
Expand Down Expand Up @@ -695,10 +736,13 @@ func feSquare(h, f *fieldElement) {
// Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
//
// |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
//
// |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
//
// See fe_mul.c for discussion of implementation strategy.
func feSquare2(h, f *fieldElement) {
f0 := f[0]
Expand Down
93 changes: 93 additions & 0 deletions group/edwards25519/fe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package edwards25519

import (
"math/big"
"testing"

"github.com/stretchr/testify/assert"
"go.dedis.ch/kyber/v4/xof/blake2xb"
)

func Test_feToBnEdgeCase(t *testing.T) {
fieldElems := []fieldElement{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, -1, 1, -1, 1, -1, 1, -1, 1, -1},
{123312, 54, 36467, 64465, 23524, 235, 234532, 643, 8975, 74654},
{12323312, -54, 356477, -69965, -23538, 32235, -233492, -643, 348975, 9174654},
}

expectedInts := []string{
"0",
"1",
"17254366098375493971863732723163371589623513702264028891549843847118849",
"57896042893221536725152487541740382065544292822329234251877658128066988212206",
"128810743174081990895079563873863294634158893429674322163950556506889511344",
"15830283690864357567092656272836221286294103082314903268964457249510342265328",
}

actualBn := big.NewInt(0)
for i, c := range fieldElems {
feToBn(actualBn, &c)
assert.Equal(t, expectedInts[i], actualBn.String())
}
}

func Test_feBnConversionRandom(t *testing.T) {
AnomalRoil marked this conversation as resolved.
Show resolved Hide resolved
seed := "feToBn"
rng := blake2xb.New([]byte(seed))

// Prepare 2 random numbers
var fe0 fieldElement
var fe1 fieldElement
var fe2 fieldElement
l := 32
p0 := make([]byte, l)
p1 := make([]byte, l)
p2 := make([]byte, l)

s, err := rng.Read(p0)
assert.NoError(t, err)
assert.Equal(t, s, l)

s, err = rng.Read(p1)
assert.NoError(t, err)
assert.Equal(t, s, l)

s, err = rng.Read(p2)
assert.NoError(t, err)
assert.Equal(t, s, l)

b0 := big.NewInt(0).SetBytes(p0)
b0 = b0.Mod(b0, prime)

b1 := big.NewInt(0).SetBytes(p1)
b0 = b1.Mod(b1, prime)

b2 := big.NewInt(0).SetBytes(p2)
b2 = b1.Mod(b2, prime)

// Convert big.Int to fieldElement
feFromBn(&fe0, b0)
feFromBn(&fe1, b1)
feFromBn(&fe2, b2)

// If we convert correctly, we should get the same result:
// (fe0 + fe1)*fe2 == (b0 + b1) * b2
var feRes fieldElement
var bExp *big.Int

feAdd(&feRes, &fe0, &fe1)
feMul(&feRes, &feRes, &fe2)

bExp = big.NewInt(0).Add(b0, b1)
bExp = big.NewInt(0).Mul(bExp, b2)
bExp = bExp.Mod(bExp, prime)

// Final conversion to compare the results
bActual := big.NewInt(0)
feToBn(bActual, &feRes)

assert.Equal(t, bExp.Cmp(bActual), 0)
}
Loading
Loading