// Copyright 2017-2018 DERO Project. All rights reserved.
|
|
// Use of this source code in any form is governed by RESEARCH license.
|
|
// license can be found in the LICENSE file.
|
|
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
|
//
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
package crypto
|
|
|
|
import "io"
|
|
import "fmt"
|
|
import "bytes"
|
|
import "crypto/rand"
|
|
import "encoding/hex"
|
|
import "encoding/binary"
|
|
|
|
const KeyLength = 32
|
|
|
|
// Key can be a Scalar or a Point
|
|
type Key [KeyLength]byte
|
|
|
|
func (k Key) MarshalText() ([]byte, error) {
|
|
return []byte(fmt.Sprintf("%x", k[:])), nil
|
|
}
|
|
|
|
func (k Key) String() string {
|
|
return fmt.Sprintf("%x", k[:])
|
|
}
|
|
|
|
func (p *Key) FromBytes(b [KeyLength]byte) {
|
|
*p = b
|
|
}
|
|
|
|
func (p *Key) ToBytes() (result [KeyLength]byte) {
|
|
result = [KeyLength]byte(*p)
|
|
return
|
|
}
|
|
|
|
// convert a hex string to a key
|
|
func HexToKey(h string) (result Key) {
|
|
byteSlice, _ := hex.DecodeString(h)
|
|
if len(byteSlice) != 32 {
|
|
panic("Incorrect key size")
|
|
}
|
|
copy(result[:], byteSlice)
|
|
return
|
|
}
|
|
|
|
func HexToHash(h string) (result Hash) {
|
|
byteSlice, _ := hex.DecodeString(h)
|
|
if len(byteSlice) != 32 {
|
|
panic("Incorrect key size")
|
|
}
|
|
copy(result[:], byteSlice)
|
|
return
|
|
}
|
|
|
|
// generates a public from the secret key
|
|
func (p *Key) PublicKey() (pubKey *Key) {
|
|
point := new(ExtendedGroupElement)
|
|
GeScalarMultBase(point, p)
|
|
pubKey = new(Key)
|
|
point.ToBytes(pubKey)
|
|
return
|
|
}
|
|
|
|
// tests whether the key is valid ( represents a point on the curve )
|
|
func (k *Key) Public_Key_Valid() bool {
|
|
var point ExtendedGroupElement
|
|
return point.FromBytes(k)
|
|
}
|
|
|
|
func (k *Key) Private_Key_Valid() bool {
|
|
return Sc_check(k)
|
|
}
|
|
|
|
// Creates a point on the Edwards Curve by hashing the key
|
|
func (p *Key) HashToEC() (result *ExtendedGroupElement) {
|
|
result = new(ExtendedGroupElement)
|
|
var p1 ProjectiveGroupElement
|
|
var p2 CompletedGroupElement
|
|
h := Key(Keccak256(p[:]))
|
|
p1.FromBytes(&h)
|
|
GeMul8(&p2, &p1)
|
|
p2.ToExtended(result)
|
|
return
|
|
}
|
|
|
|
func (p *Key) HashToPoint() (result Key) {
|
|
extended := p.HashToEC()
|
|
extended.ToBytes(&result)
|
|
return
|
|
}
|
|
|
|
// this uses random number generator from the OS
|
|
func RandomScalar() (result *Key) {
|
|
result = new(Key)
|
|
var reduceFrom [KeyLength * 2]byte
|
|
tmp := make([]byte, KeyLength*2)
|
|
rand.Read(tmp)
|
|
copy(reduceFrom[:], tmp)
|
|
ScReduce(result, &reduceFrom)
|
|
return
|
|
}
|
|
|
|
// generate a new private-public key pair
|
|
func NewKeyPair() (privKey *Key, pubKey *Key) {
|
|
privKey = RandomScalar()
|
|
pubKey = privKey.PublicKey()
|
|
return
|
|
}
|
|
|
|
func ParseKey(buf io.Reader) (result Key, err error) {
|
|
key := make([]byte, KeyLength)
|
|
if _, err = buf.Read(key); err != nil {
|
|
return
|
|
}
|
|
copy(result[:], key)
|
|
return
|
|
}
|
|
|
|
/*
|
|
//does a * G where a is a scalar and G is the curve basepoint
|
|
key scalarmultBase(const key & a) {
|
|
ge_p3 point;
|
|
key aG;
|
|
sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
|
|
ge_scalarmult_base(&point, aG.bytes);
|
|
ge_p3_tobytes(aG.bytes, &point);
|
|
return aG;
|
|
}
|
|
*/
|
|
//does a * G where a is a scalar and G is the curve basepoint
|
|
|
|
func ScalarmultBase(a Key) (aG Key) {
|
|
reduce32copy := a
|
|
ScReduce32(&reduce32copy)
|
|
point := new(ExtendedGroupElement)
|
|
GeScalarMultBase(point, &a)
|
|
point.ToBytes(&aG)
|
|
return aG
|
|
}
|
|
|
|
// generates a key which can be used as private key or mask
|
|
// this function is similiar to RandomScalar except for reduce32, TODO can we merge both
|
|
func skGen() Key {
|
|
skey := RandomScalar()
|
|
ScReduce32(skey)
|
|
return *skey
|
|
}
|
|
|
|
func (k *Key) ToExtended() (result *ExtendedGroupElement) {
|
|
result = new(ExtendedGroupElement)
|
|
result.FromBytes(k)
|
|
return
|
|
}
|
|
|
|
// bothe the function resturn identity of the ed25519 curve
|
|
func identity() (result *Key) {
|
|
result = new(Key)
|
|
result[0] = 1
|
|
return
|
|
}
|
|
func CurveIdentity() (result Key) {
|
|
result = Identity
|
|
return result
|
|
}
|
|
|
|
func CurveOrder() (result Key) {
|
|
result = L
|
|
return result
|
|
}
|
|
|
|
// convert a uint64 to a scalar
|
|
func d2h(val uint64) (result *Key) {
|
|
result = new(Key)
|
|
for i := 0; val > 0; i++ {
|
|
result[i] = byte(val & 0xFF)
|
|
val /= 256
|
|
}
|
|
return
|
|
}
|
|
|
|
func HashToScalar(data ...[]byte) (result *Key) {
|
|
result = new(Key)
|
|
*result = Key(Keccak256(data...))
|
|
ScReduce32(result)
|
|
return
|
|
}
|
|
|
|
// does a * P where a is a scalar and P is an arbitrary point
|
|
func ScalarMultKey(Point *Key, scalar *Key) (result *Key) {
|
|
P := new(ExtendedGroupElement)
|
|
P.FromBytes(Point)
|
|
resultPoint := new(ProjectiveGroupElement)
|
|
GeScalarMult(resultPoint, scalar, P)
|
|
result = new(Key)
|
|
resultPoint.ToBytes(result)
|
|
return
|
|
}
|
|
|
|
// multiply a scalar by H (second curve point of Pedersen Commitment)
|
|
func ScalarMultH(scalar *Key) (result *Key) {
|
|
h := new(ExtendedGroupElement)
|
|
h.FromBytes(&H)
|
|
resultPoint := new(ProjectiveGroupElement)
|
|
GeScalarMult(resultPoint, scalar, h)
|
|
result = new(Key)
|
|
resultPoint.ToBytes(result)
|
|
return
|
|
}
|
|
|
|
// add two points together
|
|
func AddKeys(sum, k1, k2 *Key) {
|
|
a := k1.ToExtended()
|
|
b := new(CachedGroupElement)
|
|
k2.ToExtended().ToCached(b)
|
|
c := new(CompletedGroupElement)
|
|
geAdd(c, a, b)
|
|
tmp := new(ExtendedGroupElement)
|
|
c.ToExtended(tmp)
|
|
tmp.ToBytes(sum)
|
|
return
|
|
}
|
|
|
|
// compute a*G + b*B
|
|
func AddKeys2(result, a, b, B *Key) {
|
|
BPoint := B.ToExtended()
|
|
RPoint := new(ProjectiveGroupElement)
|
|
GeDoubleScalarMultVartime(RPoint, b, BPoint, a)
|
|
RPoint.ToBytes(result)
|
|
return
|
|
}
|
|
|
|
//addKeys3
|
|
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
|
//B must be input after applying "precomp"
|
|
func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) {
|
|
A_Point := new(ExtendedGroupElement)
|
|
A_Point.FromBytes(A)
|
|
|
|
result_projective := new(ProjectiveGroupElement)
|
|
GeDoubleScalarMultPrecompVartime(result_projective, a, A_Point, b, B_Precomputed)
|
|
result_projective.ToBytes(result)
|
|
|
|
}
|
|
|
|
// subtract two points A - B
|
|
func SubKeys(diff, k1, k2 *Key) {
|
|
a := k1.ToExtended()
|
|
b := new(CachedGroupElement)
|
|
k2.ToExtended().ToCached(b)
|
|
c := new(CompletedGroupElement)
|
|
geSub(c, a, b)
|
|
tmp := new(ExtendedGroupElement)
|
|
c.ToExtended(tmp)
|
|
tmp.ToBytes(diff)
|
|
return
|
|
}
|
|
|
|
// this gives you a commitment from an amount
|
|
// this is used to convert tx fee or miner tx amount to commitment
|
|
func Commitment_From_Amount(amount uint64) Key {
|
|
return *(ScalarMultH(d2h(amount)))
|
|
}
|
|
|
|
// this is used to convert miner tx commitment to mask
|
|
// equivalent to rctOps.cpp zeroCommit
|
|
func ZeroCommitment_From_Amount(amount uint64) Key {
|
|
mask := *(identity())
|
|
mask = ScalarmultBase(mask)
|
|
am := d2h(amount)
|
|
bH := ScalarMultH(am)
|
|
AddKeys(&mask, &mask, bH)
|
|
return mask
|
|
}
|
|
|
|
// zero fill the key
|
|
func Sc_0(k *Key) {
|
|
for i := 0; i < 32; i++ {
|
|
k[i] = 0
|
|
}
|
|
}
|
|
|
|
// RandomPubKey takes a random scalar, interprets it as a point on the curve
|
|
// remember the low order bug and do more auditing of the entire thing
|
|
func RandomPubKey() (result *Key) {
|
|
result = new(Key)
|
|
p3 := new(ExtendedGroupElement)
|
|
var p1 ProjectiveGroupElement
|
|
var p2 CompletedGroupElement
|
|
h := RandomScalar()
|
|
p1.FromBytes(h)
|
|
GeMul8(&p2, &p1)
|
|
p2.ToExtended(p3)
|
|
p3.ToBytes(result)
|
|
return
|
|
}
|
|
|
|
// this is the main key derivation function and is the crux
|
|
// when deriving keys in the case user A wants to send DERO to another user B ( this is outgoing case)
|
|
// public key is B's view key
|
|
// private keys is TX private key
|
|
// if user B wants to derive key, he needs to ( this is incoming case )
|
|
// public key is TX public key
|
|
// private is B's private keys
|
|
// HOPE the above is clean and clear
|
|
|
|
func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) {
|
|
var point ExtendedGroupElement
|
|
var point2 ProjectiveGroupElement
|
|
var point3 CompletedGroupElement
|
|
|
|
if !priv.Private_Key_Valid() {
|
|
panic("Invalid private key.")
|
|
}
|
|
tmp := *pub
|
|
if !point.FromBytes(&tmp) {
|
|
panic("Invalid public key.")
|
|
}
|
|
|
|
tmp = *priv
|
|
GeScalarMult(&point2, &tmp, &point)
|
|
GeMul8(&point3, &point2)
|
|
point3.ToProjective(&point2)
|
|
|
|
point2.ToBytes(&tmp)
|
|
return tmp
|
|
}
|
|
|
|
// the origincal c implementation needs to be checked for varint overflow
|
|
// we also need to check the compatibility of golang varint with cryptonote implemented varint
|
|
// outputIndex is the position of output within that specific transaction
|
|
func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) {
|
|
tmp := make([]byte, 12, 12)
|
|
|
|
length := binary.PutUvarint(tmp, outputIndex)
|
|
tmp = tmp[:length]
|
|
|
|
var buf bytes.Buffer
|
|
buf.Write(k[:])
|
|
buf.Write(tmp)
|
|
scalar = HashToScalar(buf.Bytes())
|
|
return
|
|
}
|
|
|
|
// generate ephermal keys from a key derivation
|
|
// base key is the B's public spend key or A's private spend key
|
|
// outputIndex is the position of output within that specific transaction
|
|
func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key {
|
|
|
|
var point1, point2 ExtendedGroupElement
|
|
var point3 CachedGroupElement
|
|
var point4 CompletedGroupElement
|
|
var point5 ProjectiveGroupElement
|
|
|
|
tmp := baseKey
|
|
if !point1.FromBytes(&tmp) {
|
|
panic("Invalid public key.")
|
|
}
|
|
scalar := kd.KeyDerivationToScalar(outputIndex)
|
|
GeScalarMultBase(&point2, scalar)
|
|
point2.ToCached(&point3)
|
|
geAdd(&point4, &point1, &point3)
|
|
point4.ToProjective(&point5)
|
|
point5.ToBytes(&tmp)
|
|
return tmp
|
|
}
|
|
|
|
// generate ephermal keys from a key derivation
|
|
// base key is the A's private spend key
|
|
// outputIndex is the position of output within that specific transaction
|
|
func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key {
|
|
if !baseKey.Private_Key_Valid() {
|
|
panic("Invalid private key.")
|
|
}
|
|
scalar := kd.KeyDerivationToScalar(outputIndex)
|
|
|
|
tmp := baseKey
|
|
ScAdd(&tmp, &tmp, scalar)
|
|
return tmp
|
|
}
|
|
|
|
// NewKeyImage creates a new KeyImage from the given public and private keys.
|
|
// The keys are usually the ephemeral keys derived using KeyDerivation.
|
|
func GenerateKeyImage(pub Key, private Key) Key {
|
|
var proj ProjectiveGroupElement
|
|
|
|
ext := pub.HashToEC()
|
|
GeScalarMult(&proj, &private, ext)
|
|
|
|
var ki Key
|
|
proj.ToBytes(&ki)
|
|
return ki
|
|
}
|