This repository has been archived on 2024-04-07. You can view files and clone it, but cannot push or open issues or pull requests.
moneroutil/ringsignature.go

289 lines
6.8 KiB
Go
Raw Normal View History

2017-04-25 00:19:04 +00:00
package moneroutil
2017-05-05 03:11:50 +00:00
import (
"bytes"
2017-05-11 02:56:17 +00:00
"crypto/rand"
2017-05-05 03:11:50 +00:00
"fmt"
2017-05-11 15:22:38 +00:00
mathrand "math/rand"
2017-05-05 03:11:50 +00:00
)
const (
2017-05-11 02:56:17 +00:00
PointLength = 32
ScalarLength = 32
2017-05-05 03:11:50 +00:00
)
2017-05-11 02:56:17 +00:00
type PubKey [PointLength]byte
type PrivKey [ScalarLength]byte
2017-05-05 03:11:50 +00:00
type RingSignatureElement struct {
2017-05-11 02:56:17 +00:00
c [ScalarLength]byte
r [ScalarLength]byte
2017-05-05 03:11:50 +00:00
}
type RingSignature []*RingSignatureElement
2017-05-11 02:56:17 +00:00
func RandomScalar() (result [ScalarLength]byte) {
var reduceFrom [ScalarLength * 2]byte
tmp := make([]byte, ScalarLength*2)
rand.Read(tmp)
copy(reduceFrom[:], tmp)
ScReduce(&result, &reduceFrom)
2017-05-05 03:11:50 +00:00
return
}
2017-05-11 15:22:38 +00:00
func (p *PrivKey) FromBytes(b [ScalarLength]byte) {
*p = b
}
func (p *PrivKey) ToBytes() (result [ScalarLength]byte) {
result = [32]byte(*p)
return
}
func (p *PrivKey) PubKey() (pubKey *PubKey) {
secret := p.ToBytes()
point := new(ExtendedGroupElement)
GeScalarMultBase(point, &secret)
2017-05-11 15:22:38 +00:00
pubKeyBytes := new([PointLength]byte)
point.ToBytes(pubKeyBytes)
pubKey = (*PubKey)(pubKeyBytes)
return
}
func (p *PubKey) ToBytes() (result [PointLength]byte) {
result = [PointLength]byte(*p)
return
}
func NewKeyPair() (privKey *PrivKey, pubKey *PubKey) {
privKey = new(PrivKey)
pubKey = new(PubKey)
privKey.FromBytes(RandomScalar())
pubKey = privKey.PubKey()
return
}
2017-05-05 03:11:50 +00:00
func (s *RingSignatureElement) Serialize() (result []byte) {
2017-05-11 02:56:17 +00:00
result = make([]byte, 2*ScalarLength)
2017-05-05 03:11:50 +00:00
copy(result, s.c[:])
2017-05-11 02:56:17 +00:00
copy(result[ScalarLength:2*ScalarLength], s.r[:])
return
}
func (r *RingSignature) Serialize() (result []byte) {
for i := 0; i < len(*r); i++ {
result = append(result, (*r)[i].Serialize()...)
}
2017-05-05 03:11:50 +00:00
return
}
func ParseSignature(buf *bytes.Buffer) (result *RingSignatureElement, err error) {
s := new(RingSignatureElement)
2017-05-11 02:56:17 +00:00
c := buf.Next(ScalarLength)
if len(c) != ScalarLength {
2017-05-10 04:18:37 +00:00
err = fmt.Errorf("Not enough bytes for signature c")
2017-05-05 03:11:50 +00:00
return
}
copy(s.c[:], c)
2017-05-11 02:56:17 +00:00
r := buf.Next(ScalarLength)
if len(r) != ScalarLength {
2017-05-10 04:18:37 +00:00
err = fmt.Errorf("Not enough bytes for signature r")
2017-05-05 03:11:50 +00:00
return
}
copy(s.r[:], r)
result = s
return
}
func ParseSignatures(mixinLengths []int, buf *bytes.Buffer) (signatures []RingSignature, err error) {
// mixinLengths is the number of mixins at each input position
sigs := make([]RingSignature, len(mixinLengths), len(mixinLengths))
for i, nMixin := range mixinLengths {
sigs[i] = make([]*RingSignatureElement, nMixin, nMixin)
for j := 0; j < nMixin; j++ {
sigs[i][j], err = ParseSignature(buf)
if err != nil {
return
}
}
}
signatures = sigs
return
}
// hashes a pubkey into an Edwards Curve element
func HashToEC(pk *PubKey, r *ExtendedGroupElement) {
var p1 ProjectiveGroupElement
var p2 CompletedGroupElement
2017-05-11 02:56:17 +00:00
h := [PointLength]byte(Keccak256(pk[:]))
2017-05-10 14:17:19 +00:00
p1.FromBytes(&h)
GeMul8(&p2, &p1)
2017-05-05 03:11:50 +00:00
p2.ToExtended(r)
}
2017-05-11 02:56:17 +00:00
func HashToScalar(data ...[]byte) (result [ScalarLength]byte) {
2017-05-10 04:18:37 +00:00
result = Keccak256(data...)
ScReduce32(&result)
2017-05-10 04:18:37 +00:00
return
}
2017-05-11 15:22:38 +00:00
func CreateSignature(prefixHash *Hash, mixins []PubKey, privKey *PrivKey) (keyImage PubKey, pubKeys []PubKey, sig RingSignature) {
point := new(ExtendedGroupElement)
2017-05-11 15:22:38 +00:00
HashToEC(privKey.PubKey(), point)
privKeyBytes := privKey.ToBytes()
keyImagePoint := new(ProjectiveGroupElement)
GeScalarMult(keyImagePoint, &privKeyBytes, point)
2017-05-11 15:22:38 +00:00
var keyImageBytes [PointLength]byte
// convert key Image point from Projective to Extended
// in order to precompute
keyImagePoint.ToBytes(&keyImageBytes)
keyImageGe := new(ExtendedGroupElement)
2017-05-11 02:56:17 +00:00
keyImageGe.FromBytes(&keyImageBytes)
2017-05-11 15:22:38 +00:00
keyImage = PubKey(keyImageBytes)
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
2017-05-11 02:56:17 +00:00
k := RandomScalar()
2017-05-11 15:22:38 +00:00
pubKeys = make([]PubKey, len(mixins)+1)
privIndex := mathrand.Intn(len(pubKeys))
pubKeys[privIndex] = *privKey.PubKey()
2017-05-11 02:56:17 +00:00
r := make([]*RingSignatureElement, len(pubKeys))
2017-05-11 15:22:38 +00:00
var sum [ScalarLength]byte
toHash := prefixHash[:]
for i := 0; i < len(pubKeys); i++ {
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
2017-05-11 02:56:17 +00:00
var tmpEBytes, tmpPBytes [PointLength]byte
if i == privIndex {
GeScalarMultBase(tmpE, &k)
2017-05-11 02:56:17 +00:00
tmpE.ToBytes(&tmpEBytes)
toHash = append(toHash, tmpEBytes[:]...)
2017-05-11 15:22:38 +00:00
HashToEC(privKey.PubKey(), tmpE)
GeScalarMult(tmpP, &k, tmpE)
2017-05-11 02:56:17 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
} else {
2017-05-11 15:22:38 +00:00
if i > privIndex {
pubKeys[i] = mixins[i-1]
} else {
pubKeys[i] = mixins[i]
}
2017-05-11 02:56:17 +00:00
r[i] = &RingSignatureElement{
c: RandomScalar(),
r: RandomScalar(),
}
2017-05-11 15:22:38 +00:00
pubKeyBytes := pubKeys[i].ToBytes()
2017-05-11 02:56:17 +00:00
tmpE.FromBytes(&pubKeyBytes)
GeDoubleScalarMultVartime(tmpP, &r[i].c, tmpE, &r[i].r)
2017-05-11 02:56:17 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
2017-05-11 15:22:38 +00:00
HashToEC(&pubKeys[i], tmpE)
GeDoubleScalarMultPrecompVartime(tmpP, &r[i].r, tmpE, &r[i].c, &keyImagePre)
2017-05-11 02:56:17 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(&sum, &sum, &r[i].c)
2017-05-11 02:56:17 +00:00
}
}
h := HashToScalar(toHash)
r[privIndex] = new(RingSignatureElement)
ScSub(&r[privIndex].c, &h, &sum)
2017-05-11 15:22:38 +00:00
scalar := privKey.ToBytes()
ScMulSub(&r[privIndex].r, &r[privIndex].c, &scalar, &k)
2017-05-11 15:22:38 +00:00
sig = r
2017-05-11 02:56:17 +00:00
return
}
func VerifySignature(prefixHash *Hash, keyImage *PubKey, pubKeys []PubKey, ringSignature RingSignature) (result bool) {
keyImageGe := new(ExtendedGroupElement)
2017-05-11 02:56:17 +00:00
keyImageBytes := [PointLength]byte(*keyImage)
if !keyImageGe.FromBytes(&keyImageBytes) {
result = false
return
}
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
2017-05-05 03:11:50 +00:00
toHash := prefixHash[:]
2017-05-11 02:56:17 +00:00
var tmpS, sum [ScalarLength]byte
2017-05-05 03:11:50 +00:00
for i, pubKey := range pubKeys {
2017-05-11 02:56:17 +00:00
rse := ringSignature[i]
if !ScValid(&rse.c) || !ScValid(&rse.r) {
result = false
return
}
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
2017-05-11 02:56:17 +00:00
pubKeyBytes := [PointLength]byte(pubKey)
if !tmpE.FromBytes(&pubKeyBytes) {
result = false
return
}
2017-05-11 02:56:17 +00:00
var tmpPBytes, tmpEBytes [PointLength]byte
GeDoubleScalarMultVartime(tmpP, &rse.c, tmpE, &rse.r)
2017-05-05 03:11:50 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
2017-05-11 02:56:17 +00:00
HashToEC(&pubKey, tmpE)
2017-05-05 03:11:50 +00:00
tmpE.ToBytes(&tmpEBytes)
GeDoubleScalarMultPrecompVartime(tmpP, &rse.r, tmpE, &rse.c, &keyImagePre)
2017-05-05 03:11:50 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(&sum, &sum, &rse.c)
2017-05-05 03:11:50 +00:00
}
2017-05-10 04:18:37 +00:00
tmpS = HashToScalar(toHash)
ScSub(&sum, &tmpS, &sum)
result = ScIsZero(&sum)
2017-05-05 03:11:50 +00:00
return
}
/* Below are structs for the CT version */
2017-04-25 00:19:04 +00:00
type Key [32]byte
type ctKey struct {
destination Key
mask Key
}
type ecdhTuple struct {
mask Key
amount Key
senderPk Key
}
type RingSignatureBase struct {
ringSigType uint8
message Key
mixRing [][]ctKey
pseudoOuts []Key
ecdhInfo []ecdhTuple
outPk []ctKey
fee uint64
}
type Key64 [64]Key
type boroSig struct {
s0 Key64
s1 Key64
ee Key
}
type mgSig struct {
ss [][]Key
cc Key
ii []Key
}
type rangeSig struct {
asig boroSig
ci Key64
}
type RctSigPrunable struct {
rangeSigs []rangeSig
MGs []mgSig
}
2017-05-05 03:11:50 +00:00
type RingSignatureCT struct {
2017-04-25 00:19:04 +00:00
RingSignatureBase
RctSigPrunable
}