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

Constant-time scalars in ed25519, and variable-time option flag #173

Merged
merged 34 commits into from
Jun 30, 2017
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9f4aa73
Add SetVarTime methods to Point and Scalar interfaces,
bford Jun 3, 2017
bb3867e
new scalar code partly working, but not fully
bford Jun 3, 2017
bce2b89
fix primeOrder, cofactor, etc to be plain big.Ints normally
bford Jun 3, 2017
6eaf519
fixed endianness loss bug in mod.Int.InitBytes
bford Jun 4, 2017
a1133fc
constant-time sub prototyped but not yet working
bford Jun 4, 2017
51b50f6
got new constant-time scalars working it seems
bford Jun 4, 2017
6bb64f7
fixed arithmetic-in-place bug in projective edwards code
bford Jun 4, 2017
bad1135
simplify the scalar code just a bit
bford Jun 4, 2017
31a5cbb
fix Clone state sharing bugs
bford Jun 4, 2017
c6cdb80
constant time inversion
Jun 13, 2017
9e83790
.travis.yml changed import path to gopkg.in/dedis/kyber.v1
Jun 14, 2017
7d5f0fd
flag added on nist/ and curve25519/
Jun 14, 2017
a76faaf
removing vartime method from Scalar
Jun 15, 2017
3c81136
Merge branch 'v1' into scalars
Jun 15, 2017
f36ae2e
adding vartime to curve25519 test
Jun 15, 2017
0e78656
Merge branch 'v1' into scalars
Jun 15, 2017
59a897f
changing to ed25519 example + fixing endianness in ed25519 scalar
Jun 15, 2017
2d953ff
no more bugs ;)
Jun 15, 2017
6b77576
back to SetVarTime for scalar
Jun 15, 2017
b3da6d2
fixing curve25519 (wrong branch, supposed to be in v1)
Jun 15, 2017
294eef9
comments from @ineiti
Jun 15, 2017
f5608af
ineiti's comments round #2
Jun 16, 2017
f5f7ebb
Panicking in mod.Int if variable time is false
Jun 16, 2017
e72ba4d
removed comment XXX big.int + benchs
Jun 19, 2017
20e3545
comments from ineiti + linting
Jun 20, 2017
3baf54d
ineiti's comment round #3
Jun 21, 2017
1946b38
screduce in own function test
Jun 21, 2017
0bcf70c
pushing benchmarks implementations details
Jun 21, 2017
0d09f3c
changing setvartime API + implementations
Jun 21, 2017
28a0871
removed XXX comment
Jun 21, 2017
bc5f664
Comments
ineiti Jun 21, 2017
ebd2462
comment-patches
ineiti Jun 21, 2017
644dc22
Merge pull request #180 from dedis/ineiti-patch-1
nikkolasg Jun 21, 2017
7b0afeb
golint is happy. Added exception for NORX code
Jun 29, 2017
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls


script:
- make test

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ test_verbose:
test_goverall:
${GOPATH}/bin/goveralls -service=travis-ci

test: test_goverall
test: test_fmt test_goverall
8 changes: 5 additions & 3 deletions cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,13 @@ type option struct{ name string }

func (o *option) String() string { return o.name }

// Pass NoKey to a Cipher constructor to create an unkeyed Cipher.
// NoKey is given to a Cipher constructor to create an unkeyed
// Cipher.
var NoKey = []byte{}

// Pass RandomKey to a Cipher constructor to create a randomly seeded Cipher.
var RandomKey []byte = nil
// RandomKey is given to a Cipher constructor to create a
// randomly seeded Cipher.
var RandomKey []byte

// Cipher represents a general-purpose symmetric message cipher.
// A Cipher instance embodies a scalar that may be used to encrypt/decrypt data
Expand Down
2 changes: 1 addition & 1 deletion cipher/aead.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type cipherAEAD struct {
kyber.Cipher
}

// Wrap an kyber.message Cipher to implement
// NewAEAD wraps an kyber.message Cipher to implement
// the Authenticated Encryption with Associated Data (AEAD) interface.
func NewAEAD(c kyber.Cipher) cipher.AEAD {
return &cipherAEAD{c}
Expand Down
6 changes: 3 additions & 3 deletions cipher/bench/cipher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import (
"crypto/rc4"
"testing"

"golang.org/x/crypto/blowfish"
"golang.org/x/crypto/salsa20"
"golang.org/x/crypto/twofish"
"gopkg.in/dedis/kyber.v1"
"gopkg.in/dedis/kyber.v1/cipher/aes"
"gopkg.in/dedis/kyber.v1/cipher/norx"
"gopkg.in/dedis/kyber.v1/cipher/sha3"
"golang.org/x/crypto/blowfish"
"golang.org/x/crypto/salsa20"
"golang.org/x/crypto/twofish"
)

var buf = make([]byte, 1024*1024)
Expand Down
2 changes: 1 addition & 1 deletion cipher/bench/doc.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// This package exists runs comparative benchmarks
// Package bench runs comparative benchmarks
// across several alternative Cipher implementations.
package bench
2 changes: 1 addition & 1 deletion cipher/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"gopkg.in/dedis/kyber.v1"
)

// Construct a general message Cipher
// FromBlock constructs a general message Cipher
// from a Block cipher and a cryptographic Hash.
func FromBlock(newCipher func(key []byte) (cipher.Block, error),
newHash func() hash.Hash, blockLen, keyLen, hashLen int,
Expand Down
3 changes: 3 additions & 0 deletions cipher/cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import (
"crypto/cipher"
)

// Stream is just an alias for cipher.Stream
type Stream cipher.Stream

// Block is just an alias for cipher.Block
type Block cipher.Block
1 change: 1 addition & 0 deletions cipher/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type cipherBlockSize interface {
BlockSize() int
}

// NewHash returns a new cipher-based hash
func NewHash(cipher func(key []byte, options ...interface{}) kyber.Cipher, size int) hash.Hash {
ch := &cipherHash{}
ch.cipher = cipher
Expand Down
4 changes: 2 additions & 2 deletions cipher/sponge.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type spongeCipher struct {
pos int
}

// SpongeCipher builds a general message Cipher from a Sponge function.
// FromSponge builds a general message Cipher from a Sponge function.
func FromSponge(sponge Sponge, key []byte, options ...interface{}) kyber.Cipher {
sc := spongeCipher{}
sc.sponge = sponge
Expand All @@ -87,7 +87,7 @@ func FromSponge(sponge Sponge, key []byte, options ...interface{}) kyber.Cipher
// Setup normal-case domain-separation byte used for message payloads
sc.setDomain(domainPayload, 0)

return kyber.Cipher{&sc}
return kyber.Cipher{CipherState: &sc}
}

func (sc *spongeCipher) parseOptions(options []interface{}) bool {
Expand Down
9 changes: 5 additions & 4 deletions cipher/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const bufLen = 1024

var zeroBytes = make([]byte, bufLen)

// Construct a general message Cipher
// FromStream constructs a general message Cipher
// from a Stream cipher and a cryptographic Hash.
func FromStream(newStream func(key []byte) cipher.Stream,
newHash func() hash.Hash, blockLen, keyLen, hashLen int,
Expand All @@ -52,7 +52,7 @@ func FromStream(newStream func(key []byte) cipher.Stream,
panic("no FromStream options supported yet")
}

return kyber.Cipher{&sc}
return kyber.Cipher{CipherState: &sc}
}

func (sc *streamCipher) Partial(dst, src, key []byte) {
Expand Down Expand Up @@ -80,10 +80,11 @@ func (sc *streamCipher) Partial(dst, src, key []byte) {
// absorb cryptographic input (which may overlap with dst)
if key != nil {
nkey := ints.Min(n, len(key)) // # key bytes available
sc.h.Write(key[:nkey])
// XXX check return error ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact an error-check here would be very nice. But as the main method does not return any error, I'm not sure what is best to do here.

So either remove the _, _ = or do some error-checking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Golint

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the XXX can go away.

_, _ = sc.h.Write(key[:nkey])
if n > nkey {
buf := make([]byte, n-nkey)
sc.h.Write(buf)
_, _ = sc.h.Write(buf)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Package crypto provides a toolbox of advanced cryptographic primitives,
Package kyber provides a toolbox of advanced cryptographic primitives,
for applications that need more than straightforward signing and encryption.
The cornerstone of this toolbox is the 'kyber. sub-package,
which defines kyber.interfaces to cryptographic primitives
Expand Down
11 changes: 5 additions & 6 deletions encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"crypto/cipher"
"encoding"
"encoding/binary"
"errors"
"fmt"
"io"
"reflect"
Expand Down Expand Up @@ -143,7 +142,7 @@ type decoder struct {
r io.Reader
}

var int32Type reflect.Type = reflect.TypeOf(int32(0))
var int32Type = reflect.TypeOf(int32(0))

// Read a series of binary objects from an io.Reader.
// The objs must be a list of pointers.
Expand Down Expand Up @@ -217,7 +216,7 @@ func (de *decoder) value(v reflect.Value, depth int) error {
var i int32
err := binary.Read(de.r, binary.BigEndian, &i)
if err != nil {
return errors.New(fmt.Sprintf("Error converting int to int32 ( %v )", err))
return fmt.Errorf("Error converting int to int32 ( %v )", err)
}
v.SetInt(int64(i))
return err
Expand Down Expand Up @@ -314,7 +313,7 @@ func (en *encoder) value(obj interface{}, depth int) error {
return nil
}

// Default implementation of reflective constructor for ciphersuites
// SuiteNew is the Default implementation of reflective constructor for ciphersuites
func SuiteNew(g Group, t reflect.Type) interface{} {
switch t {
case tScalar:
Expand All @@ -325,12 +324,12 @@ func SuiteNew(g Group, t reflect.Type) interface{} {
return nil
}

// Default implementation of Encoding interface Read for ciphersuites
// SuiteRead is the default implementation of Encoding interface Read for ciphersuites
func SuiteRead(s Constructor, r io.Reader, objs ...interface{}) error {
return BinaryEncoding{Constructor: s}.Read(r, objs)
}

// Default implementation of Encoding interface Write for ciphersuites
// SuiteWrite is the default implementation of Encoding interface Write for ciphersuites
func SuiteWrite(s Constructor, w io.Writer, objs ...interface{}) error {
return BinaryEncoding{Constructor: s}.Write(w, objs)
}
4 changes: 2 additions & 2 deletions examples/dh_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package examples

import (
"gopkg.in/dedis/kyber.v1/group/nist"
"gopkg.in/dedis/kyber.v1/group/edwards25519"
"gopkg.in/dedis/kyber.v1/util/random"
)

Expand All @@ -15,7 +15,7 @@ simply by changing the first line that picks the suite.
func Example_diffieHellman() {

// Crypto setup: NIST-standardized P256 curve with AES-128 and SHA-256
suite := nist.NewAES128SHA256P256()
suite := edwards25519.NewAES128SHA256Ed25519(false)

// Alice's public/private keypair
a := suite.Scalar().Pick(random.Stream) // Alice's private key
Expand Down
4 changes: 2 additions & 2 deletions examples/enc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package examples

import (
"gopkg.in/dedis/kyber.v1"
"gopkg.in/dedis/kyber.v1/group/nist"
"gopkg.in/dedis/kyber.v1/group/edwards25519"
"gopkg.in/dedis/kyber.v1/util/random"
)

Expand Down Expand Up @@ -58,7 +58,7 @@ see for example anon.Encrypt, which encrypts a message for
one of several possible receivers forming an explicit anonymity set.
*/
func Example_elGamalEncryption() {
group := nist.NewAES128SHA256P256()
group := edwards25519.NewAES128SHA256Ed25519(false)

// Create a public/private keypair
a := group.Scalar().Pick(random.Stream) // Alice's private key
Expand Down
2 changes: 1 addition & 1 deletion examples/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This package provides a suite of tests showing how to use the different
// Package examples provides a suite of tests showing how to use the different
// abstraction and protocols provided by the dedis/kyber library. To run the
// tests, simply do `go test -v`.
//
Expand Down
16 changes: 8 additions & 8 deletions examples/sig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"fmt"

"gopkg.in/dedis/kyber.v1"
"gopkg.in/dedis/kyber.v1/group/nist"
"gopkg.in/dedis/kyber.v1/group/edwards25519"
)

type Suite interface {
Expand Down Expand Up @@ -54,7 +54,7 @@ func SchnorrSign(suite Suite, random cipher.Stream, message []byte,
// And check that hashElgamal for T and the message == c
buf := bytes.Buffer{}
sig := basicSig{c, r}
suite.Write(&buf, &sig)
_ = suite.Write(&buf, &sig)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again error-checking: either remove _ = or do some error-checking.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Golint.

return buf.Bytes()
}

Expand Down Expand Up @@ -87,9 +87,9 @@ func SchnorrVerify(suite Suite, message []byte, publicKey kyber.Point,
}

// Example of using Schnorr
func ExampleSchnorr() {
func Example_schnorr() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Golint do not pass with that so I choose golint.

// Crypto setup
group := nist.NewAES128SHA256P256()
group := edwards25519.NewAES128SHA256Ed25519(false)
rand := group.Cipher([]byte("example"))

// Create a public/private keypair (X,x)
Expand All @@ -110,9 +110,9 @@ func ExampleSchnorr() {

// Output:
// Signature:
// 00000000 c1 7a 91 74 06 48 5d 53 d4 92 27 71 58 07 eb d5 |.z.t.H]S..'qX...|
// 00000010 75 a5 89 92 78 67 fc b1 eb 36 55 63 d1 32 12 20 |u...xg...6Uc.2. |
// 00000020 2c 78 84 81 04 0d 2a a8 fa 80 d0 e8 c3 14 65 e3 |,x....*.......e.|
// 00000030 7f f2 7c 55 c5 d2 c6 70 51 89 40 cd 63 50 bf c6 |..|U...[email protected]..|
// 00000000 d4 64 bd ac 8a 06 d9 71 f4 ae a1 da e1 c5 55 d5 |.d.....q......U.|
// 00000010 f7 89 50 10 a5 d9 99 52 b0 c4 f2 ba f9 37 67 02 |..P....R.....7g.|
// 00000020 35 3e 9b ac e6 dd d1 98 f6 19 88 37 4d e3 4f 5c |5>.........7M.O\|
// 00000030 36 de a7 bf b9 f0 06 2b 72 6f 81 b7 59 19 c6 00 |6......+ro..Y...|
// Signature verified against correct message.
}
23 changes: 18 additions & 5 deletions group.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,18 @@ type Scalar interface {
// Set to a fresh random or pseudo-random scalar
Pick(rand cipher.Stream) Scalar

// SetBytes will take bytes and create a scalar out of it
// SetBytes sets the scalar from a big-endian byte-slice,
// reducing if necessary to the appropriate modulus.
SetBytes([]byte) Scalar

// Bytes returns the raw internal representation
// Bytes returns a big-Endian representation of the scalar
Bytes() []byte

// Allow or disallow use of faster variable-time implementations
// of operations on this Point, returning the old flag value.
// This flag always defaults to false (constant-time only)
// in implementations that can provide constant-time operations.
SetVarTime(varTime bool) bool
Copy link
Collaborator

@nikkolasg nikkolasg Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that we are not providing the variable time implementation anymore for Scalars in edwards25519/ anymore. The simplest way to do it would be to add if s.varTime { .. } else { ... } in every method of the Scalar... Having this "dual state" / dual implementation in one struct does not look very nice at all and has its pile of drawbacks (maintability, readability mainly).
May I propose an alternative approach ;) ?

What about if we change the signature to

type Scalar interface {
  ...
  // VarTime returns a Scalar using variable time arithmetic operations if varTime is true. 
  // It returns a constant time implementation of a Scalar if varTime is false. 
  VarTime(varTime bool) Scalar // plus the old value if needed ?
}

so in our implementation we can have a clear distinction between the two implementations

type scalarVarTime mod.Int

type scalarConstTime struct  {
   v [32]byte
}

I see at least two main advantages here:

  1. API-wise:
  • not keeping track on "which state are we on" for a specific scalar.
  • consistency with other methods that returns the result as Scalar
  1. Implementation-wise: it's much cleaner and easier to code separate implementation, one vartime and one const. time. If I were a new developer hacking on this library, I'd find that much more elegant than having if / else in every methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of this approach, and I'm open to it but still on the fence about it. The main downsides I see are:

  • It makes constant-time-Scalars and variable-time-Scalars (for the same Suite) different and incompatible by default, in that you can't for example add a variable-time Scalar to a constant-time Scalar and such without doing awkward conversions. The need for constant-time operations is often typically specific to particular values - i.e., whether that particular value involves secret information or not - and a lot of calculations in practice involve a combination of secret and non-secret values. Potentially mitigating this downside somewhat, it might be the case that most of the non-secret values we work with tend to be Points and not Scalars - but if so, that would suggest just making Scalar arithmetic constant-time-only and not bothering to provide faster variable-time versions at all.

  • The other functions in the same Suite, particular point.Mul, need to know how to detect and deal with two different types of scalar types: i.e., point.Mul will have to do a type-switch test whether the scalar that was passed as the parameter is actually a scalarVarTime or a scalarConstTime. Not a big deal and perfectly doable, but a slight cost in complexity and perhaps time (type tests tend to be more expensive than just checking a bool flag, though probably not significant compared to the total cost of a scalar multiply).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it would be worth taking a bit of a "census" throughout the crypto and/or onet code to see where all we do Scalar arithmetic and how much of that arithmetic might conceivably benefit from being able to use a faster variable-time version for non-sensitive calculations? If it turns out there's not all that much, and/or it proves hard to identify and disentangle which are the "sensitive" vs "non-sensitive" scalars, then I would propose in this case it's probably best (certainly safest) just to make the scalars always use constant-time arithmetic and take whatever performance hit that means.

Given that point.Mul is the main performance-critical operation we're concerned about in general, perhaps keeping that as the only one we bother with having constant-time and variable-time versions of would be perfectly fine.

Copy link
Collaborator

@nikkolasg nikkolasg Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, it's a valid counter argument indeed.

I am totally in favor of dropping variable time implementation for Scalar, following in spirit the well-coded scalar implementation in dalek for example.

From my experience with the kyber library and the algorithms I coded, I don't think it should be that hard to distinguish between sensitive or non sensitive scalars if one really takes the time at each individual operations. Nevertheless, my main concern is that screw-ups can and will happen (Murphy's law!). Removing vartime implementation will at least prevent a large range of potential weaknesses in existant and future implementations: that's a huge benefit. While this library must not be slow, its aim is not to be the fastest also, it's to be a generic low-level and secure cryptographic library, so the performance cost is totally bearable in my opinion in constrast to the benefits.

}

/*
Expand Down Expand Up @@ -111,13 +118,19 @@ type Point interface {
// Set to the negation of point a
Neg(a Point) Point

// Encrypt point p by multiplying with scalar s.
// If p == nil, encrypt the standard base point Base().
// Multiply point p by the scalar s.
// If p == nil, multiply with the standard base point Base().
Mul(s Scalar, p Point) Point

// Allow or disallow use of faster variable-time implementations
// of operations on this Point. Returns the old flag value.
// This flag always defaults to false (constant-time only)
// in implementations that can provide constant-time operations.
SetVarTime(varTime bool) bool
}

/*
This interface represents an kyber.cryptographic group
Group interface represents an kyber.cryptographic group
usable for Diffie-Hellman key exchange, ElGamal encryption,
and the related body of public-key cryptographic algorithms
and zero-knowledge proof methods.
Expand Down
31 changes: 25 additions & 6 deletions group/curve25519/basic.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build experimental
// +build experimental vartime

package curve25519

Expand Down Expand Up @@ -86,6 +86,12 @@ func (P *basicPoint) Set(P2 kyber.Point) kyber.Point {
return P
}

func (P *basicPoint) Clone() kyber.Point {
p2 := new(basicPoint)
p2.Set(P)
return p2
}

// Set to the neutral element, which is (0,1) for twisted Edwards curves.
func (P *basicPoint) Null() kyber.Point {
P.Set(&P.c.null)
Expand All @@ -98,19 +104,28 @@ func (P *basicPoint) Base() kyber.Point {
return P
}

func (P *basicPoint) PickLen() int {
return P.c.pickLen()
func (P *basicPoint) EmbedLen() int {
return P.c.embedLen()
}

func (P *basicPoint) Embed(data []byte, rand cipher.Stream) kyber.Point {
P.c.embed(P, data, rand)
return P
}

func (P *basicPoint) Pick(data []byte, rand cipher.Stream) (kyber.Point, []byte) {
return P, P.c.pickPoint(P, data, rand)
func (P *basicPoint) Pick(rand cipher.Stream) kyber.Point {
return P.Embed(nil, rand)
}

// Extract embedded data from a point group element
func (P *basicPoint) Data() ([]byte, error) {
return P.c.data(&P.x, &P.y)
}

func (P *basicPoint) SetVarTime(varTime bool) bool {
return true
}

// Add two points using the basic unified addition laws for Edwards curves:
//
// x' = ((x1*y2 + x2*y1) / (1 + d*x1*x2*y1*y2))
Expand Down Expand Up @@ -167,7 +182,7 @@ func (P *basicPoint) Neg(A kyber.Point) kyber.Point {
func (P *basicPoint) Mul(s kyber.Scalar, G kyber.Point) kyber.Point {
v := s.(*mod.Int).V
if G == nil {
return P.Base().Mul(P, s)
return P.Base().Mul(s, P)
}
T := P
if G == P { // Must use temporary in case G == P
Expand Down Expand Up @@ -206,6 +221,10 @@ func (c *BasicCurve) Point() kyber.Point {
return P
}

func (c *BasicCurve) NewKey(r cipher.Stream) kyber.Scalar {
return c.Scalar().Pick(r)
}

// Initialize the curve with given parameters.
func (c *BasicCurve) Init(p *Param, fullGroup bool) *BasicCurve {
c.curve.init(c, p, fullGroup, &c.null, &c.base)
Expand Down
Loading