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

Wrap btcec's secp256k1 implementation for kyber.{Group,Point,Scalar} #385

Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

1 go.mod
@@ -1,6 +1,7 @@
module go.dedis.ch/kyber/v3

require (
github.com/btcsuite/btcd v0.0.0-20190410025418-9bfb2ca0346b

This comment has been minimized.

Copy link
@jeffallen

jeffallen May 22, 2019

Contributor

btcd is a rather large dependency, since all we really want is btcec. Their license (the ISC license) would allow us to fork their code, and bring in btcec directly into Kyber if we wanted. btcec is fairly stable, having received just a couple commits in 2 years.

Did you consider incorporating btcec as source instead of as a dependency?

This comment has been minimized.

Copy link
@coventry

coventry May 22, 2019

Author

No, I hadn't, but I'd be happy to do that if the licence allows, and expect it would be a straightforward modification.

This comment has been minimized.

Copy link
@jeffallen

jeffallen May 24, 2019

Contributor

Yes, please.

github.com/stretchr/testify v1.3.0
go.dedis.ch/fixbuf v1.0.3
go.dedis.ch/protobuf v1.0.5
30 go.sum
@@ -1,15 +1,45 @@
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.0.0-20190410025418-9bfb2ca0346b h1:7J7sEce3LgtbMgs7PKcN61gF3b4txM6SjaRoJTSk640=
github.com/btcsuite/btcd v0.0.0-20190410025418-9bfb2ca0346b/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
go.dedis.ch/protobuf v1.0.5 h1:EbF1czEKICxf5KY8Tm7wMF28hcOQbB6yk4IybIFWTYE=
go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b h1:Elez2XeF2p9uyVj0yEUDqQ56NFcDtcBNkYP7yv8YbUE=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e h1:3GIlrlVLfkoipSReOMNAgApI0ajnalyLa/EZHHca/XI=
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -0,0 +1,41 @@
// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
// interfaces, based on btcd/btcec and kyber/group/mod
//
// XXX: NOT CONSTANT TIME!
package secp256k1

import (
"math/big"

secp256k1BTCD "github.com/btcsuite/btcd/btcec"

This comment has been minimized.

Copy link
@jeffallen

jeffallen May 24, 2019

Contributor

Why do you rename the package here? Anyway, with the inclusion of the btcec code, this will all be local and not imported.

You should include the minimum of the btcec code you can, for example not ciphering.go, etc. Probably just ScalarBaseMult and ScalarMult and their dependencies, including the pre-computed point table. Furthermore, you can leave gensecp256k1.go and genprecomps.go out, just change the comment in secp256k1.go to explain where it came from (i.e. the real btcec package).

This comment has been minimized.

Copy link
@coventry

coventry May 24, 2019

Author

I just found the name btcec obscure.


"go.dedis.ch/kyber/v3"
)

// Secp256k1 represents the secp256k1 group.
// There are no parameters and no initialization is required
// because it supports only this one specific curve.
type Secp256k1 struct{}

// s256 is the btcec representation of secp256k1.
var s256 *secp256k1BTCD.KoblitzCurve = secp256k1BTCD.S256()

// String returns the name of the curve
func (*Secp256k1) String() string { return "Secp256k1" }

var egScalar kyber.Scalar = newScalar(big.NewInt(0))
var egPoint kyber.Point = &secp256k1Point{newFieldZero(), newFieldZero()}

// ScalarLen returns the length of a marshalled Scalar
func (*Secp256k1) ScalarLen() int { return egScalar.MarshalSize() }

// Scalar creates a new Scalar for the prime-order group on the secp256k1 curve
func (*Secp256k1) Scalar() kyber.Scalar { return newScalar(big.NewInt(0)) }

// PointLen returns the length of a marshalled Point
func (*Secp256k1) PointLen() int { return egPoint.MarshalSize() }

// Point returns a new secp256k1 point
func (*Secp256k1) Point() kyber.Point {
return &secp256k1Point{newFieldZero(), newFieldZero()}
}
@@ -0,0 +1,169 @@
// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar}
// interfaces, based on btcd/btcec and kyber/group/mod
//
// XXX: NOT CONSTANT TIME!
package secp256k1

// Arithmetic operations in the base field of secp256k1, i.e. ℤ/qℤ, where q is
// the base field characteristic.

import (
"crypto/cipher"
"fmt"
"math/big"

"go.dedis.ch/kyber/v3/util/random"
)

// q is the field characteristic (cardinality) of the secp256k1 base field. All
// arithmetic operations on the field are modulo this.
var q = s256.P

type fieldElt big.Int

// newFieldZero returns a newly allocated field element.
func newFieldZero() *fieldElt { return (*fieldElt)(big.NewInt(0)) }

// newBigInt allocates a new big.Int and returns it
func newBigInt() *big.Int { return big.NewInt(0) }

// Int returns f as a big.Int
func (f *fieldElt) int() *big.Int { return (*big.Int)(f) }

// modQ reduces f's underlying big.Int modulo q, and returns it
func (f *fieldElt) modQ() *fieldElt {
if f.int().Cmp(q) != -1 || f.int().Cmp(bigZero) == -1 {
// f ∉ {0, ..., q-1}. Find the representative of f+qℤ in that set.
//
// Per Mod docstring, "Mod implements Euclidean modulus", meaning that after
// this, f will be the smallest non-negative representative of its
// equivalence class in ℤ/qℤ. TODO(alx): Make this faster
f.int().Mod(f.int(), q)
}
return f
}

// This differs from SetInt below, in that it does not take a copy of v.
func fieldEltFromBigInt(v *big.Int) *fieldElt { return (*fieldElt)(v).modQ() }

func fieldEltFromInt(v int64) *fieldElt {
return fieldEltFromBigInt(big.NewInt(int64(v))).modQ()
}

var fieldZero = fieldEltFromInt(0)
var bigZero = big.NewInt(0)

// String returns the string representation of f
func (f *fieldElt) String() string {
return fmt.Sprintf("fieldElt{%x}", f.int())
}

// Equal returns true iff f=g, i.e. the backing big.Ints satisfy f ≡ g mod q
func (f *fieldElt) Equal(g *fieldElt) bool {
if f == (*fieldElt)(nil) && g == (*fieldElt)(nil) {
return true
}
if f == (*fieldElt)(nil) { // f is nil, g is not
return false
}
if g == (*fieldElt)(nil) { // g is nil, f is not
return false
}
return bigZero.Cmp(newFieldZero().Sub(f, g).modQ().int()) == 0
}

// Add sets f to the sum of a and b modulo q, and returns it.
func (f *fieldElt) Add(a, b *fieldElt) *fieldElt {
f.int().Add(a.int(), b.int())
return f.modQ()
}

// Sub sets f to a-b mod q, and returns it.
func (f *fieldElt) Sub(a, b *fieldElt) *fieldElt {
f.int().Sub(a.int(), b.int())
return f.modQ()
}

// Set sets f's value to v, and returns f.
func (f *fieldElt) Set(v *fieldElt) *fieldElt {
f.int().Set(v.int())
return f.modQ()
}

// SetInt sets f's value to v mod q, and returns f.
func (f *fieldElt) SetInt(v *big.Int) *fieldElt {
f.int().Set(v)
return f.modQ()
}

// Pick samples uniformly from {0, ..., q-1}, assigns sample to f, and returns f
func (f *fieldElt) Pick(rand cipher.Stream) *fieldElt {
return f.SetInt(random.Int(q, rand))
}

// Neg sets f to the negation g modulo q, and retruns it
func (f *fieldElt) Neg(g *fieldElt) *fieldElt {
f.int().Neg(g.int())
return f.modQ()
}

// Clone returns a new fieldElt, backed by a clone of f
func (f *fieldElt) Clone() *fieldElt { return newFieldZero().Set(f.modQ()) }

// SetBytes sets f to the 32-byte big-endian value represented by buf, reduces
// it, and returns it.
func (f *fieldElt) SetBytes(buf [32]byte) *fieldElt {
f.int().SetBytes(buf[:])
return f.modQ()
}

// Bytes returns the 32-byte big-endian representation of f
func (f *fieldElt) Bytes() [32]byte {
bytes := f.modQ().int().Bytes()
if len(bytes) > 32 {
panic("field element longer than 256 bits")
}
var rv [32]byte
copy(rv[32-len(bytes):], bytes) // leftpad w zeros
return rv
}

var two = big.NewInt(2)

// square returns y² mod q
func fieldSquare(y *fieldElt) *fieldElt {
return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q))
}

// sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See
// https://math.stackexchange.com/a/1816280, for instance
//
// What I'm calling sqrtPower is called q on the s256 struct. (See
// btcec.initS256), which is confusing because the "Q" in "QPlus1Div4" refers to
// the field characteristic
var sqrtPower = s256.QPlus1Div4()

// maybeSqrtInField returns a square root of v, if it has any, else nil
func maybeSqrtInField(v *fieldElt) *fieldElt {
s := newFieldZero()
s.int().Exp(v.int(), sqrtPower, q)
if !fieldSquare(s).Equal(v) {
return nil
}
return s
}

var three = big.NewInt(3)
var seven = fieldEltFromInt(7)

// rightHandSide returns the RHS of the secp256k1 equation, x³+7 mod q, given x
func rightHandSide(x *fieldElt) *fieldElt {
xCubed := newFieldZero()
xCubed.int().Exp(x.int(), three, q)
return xCubed.Add(xCubed, seven)
}

// isEven returns true if f is even, false otherwise
func (f *fieldElt) isEven() bool {
return big.NewInt(0).Mod(f.int(), two).Cmp(big.NewInt(0)) == 0
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.