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

185 lines
4.7 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 (
"fmt"
2017-05-11 19:15:06 +00:00
"io"
"math/rand"
2017-05-05 03:11:50 +00:00
)
type RingSignatureElement struct {
2017-05-14 00:36:32 +00:00
c *Key
r *Key
2017-05-05 03:11:50 +00:00
}
type RingSignature []*RingSignatureElement
2017-05-11 19:15:06 +00:00
func (r *RingSignatureElement) Serialize() (result []byte) {
2017-05-14 00:36:32 +00:00
result = make([]byte, 2*KeyLength)
copy(result[:KeyLength], r.c[:])
copy(result[KeyLength:2*KeyLength], r.r[:])
2017-05-11 02:56:17 +00:00
return
}
func (r *RingSignature) Serialize() (result []byte) {
2017-05-14 00:36:32 +00:00
result = make([]byte, len(*r)*KeyLength*2)
2017-05-11 02:56:17 +00:00
for i := 0; i < len(*r); i++ {
2017-05-14 00:36:32 +00:00
copy(result[i*KeyLength*2:(i+1)*KeyLength*2], (*r)[i].Serialize())
}
return
}
func NewRingSignatureElement() (r *RingSignatureElement) {
r = &RingSignatureElement{
c: new(Key),
r: new(Key),
2017-05-11 02:56:17 +00:00
}
2017-05-05 03:11:50 +00:00
return
}
2017-05-11 19:15:06 +00:00
func ParseSignature(buf io.Reader) (result *RingSignatureElement, err error) {
2017-05-14 00:36:32 +00:00
rse := NewRingSignatureElement()
c := make([]byte, KeyLength)
2017-05-11 19:15:06 +00:00
n, err := buf.Read(c)
if err != nil {
return
}
2017-05-14 00:36:32 +00:00
if n != KeyLength {
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
}
2017-05-11 19:15:06 +00:00
copy(rse.c[:], c)
2017-05-14 00:36:32 +00:00
r := make([]byte, KeyLength)
2017-05-11 19:15:06 +00:00
n, err = buf.Read(r)
if err != nil {
return
}
2017-05-14 00:36:32 +00:00
if n != KeyLength {
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
}
2017-05-11 19:15:06 +00:00
copy(rse.r[:], r)
result = rse
2017-05-05 03:11:50 +00:00
return
}
2017-05-11 19:15:06 +00:00
func ParseSignatures(mixinLengths []int, buf io.Reader) (signatures []RingSignature, err error) {
2017-05-05 03:11:50 +00:00
// 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
}
2017-05-14 00:36:32 +00:00
func HashToScalar(data ...[]byte) (result *Key) {
result = new(Key)
*result = Key(Keccak256(data...))
ScReduce32(result)
2017-05-10 04:18:37 +00:00
return
}
2017-05-14 00:36:32 +00:00
func CreateSignature(prefixHash *Hash, mixins []Key, privKey *Key) (keyImage Key, pubKeys []Key, sig RingSignature) {
2017-05-11 19:15:06 +00:00
point := privKey.PubKey().HashToEC()
keyImagePoint := new(ProjectiveGroupElement)
2017-05-14 00:36:32 +00:00
GeScalarMult(keyImagePoint, privKey, point)
2017-05-11 15:22:38 +00:00
// convert key Image point from Projective to Extended
// in order to precompute
2017-05-14 00:36:32 +00:00
keyImagePoint.ToBytes(&keyImage)
keyImageGe := new(ExtendedGroupElement)
2017-05-14 00:36:32 +00:00
keyImageGe.FromBytes(&keyImage)
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
2017-05-11 02:56:17 +00:00
k := RandomScalar()
2017-05-14 00:36:32 +00:00
pubKeys = make([]Key, len(mixins)+1)
2017-05-11 19:15:06 +00:00
privIndex := rand.Intn(len(pubKeys))
2017-05-11 15:22:38 +00:00
pubKeys[privIndex] = *privKey.PubKey()
2017-05-11 02:56:17 +00:00
r := make([]*RingSignatureElement, len(pubKeys))
2017-05-14 00:36:32 +00:00
sum := new(Key)
2017-05-11 15:22:38 +00:00
toHash := prefixHash[:]
for i := 0; i < len(pubKeys); i++ {
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
2017-05-14 00:36:32 +00:00
var tmpEBytes, tmpPBytes Key
2017-05-11 02:56:17 +00:00
if i == privIndex {
2017-05-14 00:36:32 +00:00
GeScalarMultBase(tmpE, k)
2017-05-11 02:56:17 +00:00
tmpE.ToBytes(&tmpEBytes)
toHash = append(toHash, tmpEBytes[:]...)
2017-05-11 19:15:06 +00:00
tmpE = privKey.PubKey().HashToEC()
2017-05-14 00:36:32 +00:00
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-14 00:36:32 +00:00
tmpE.FromBytes(&pubKeys[i])
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 19:15:06 +00:00
tmpE = pubKeys[i].HashToEC()
2017-05-14 00:36:32 +00:00
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[:]...)
2017-05-14 00:36:32 +00:00
ScAdd(sum, sum, r[i].c)
2017-05-11 02:56:17 +00:00
}
}
h := HashToScalar(toHash)
2017-05-14 00:36:32 +00:00
r[privIndex] = NewRingSignatureElement()
ScSub(r[privIndex].c, h, sum)
ScMulSub(r[privIndex].r, r[privIndex].c, privKey, k)
2017-05-11 15:22:38 +00:00
sig = r
2017-05-11 02:56:17 +00:00
return
}
2017-05-14 00:36:32 +00:00
func VerifySignature(prefixHash *Hash, keyImage *Key, pubKeys []Key, ringSignature RingSignature) (result bool) {
keyImageGe := new(ExtendedGroupElement)
2017-05-14 00:36:32 +00:00
if !keyImageGe.FromBytes(keyImage) {
result = false
return
}
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
2017-05-05 03:11:50 +00:00
toHash := prefixHash[:]
2017-05-14 00:36:32 +00:00
tmpS, sum := new(Key), new(Key)
2017-05-05 03:11:50 +00:00
for i, pubKey := range pubKeys {
2017-05-11 02:56:17 +00:00
rse := ringSignature[i]
2017-05-14 00:36:32 +00:00
if !ScValid(rse.c) || !ScValid(rse.r) {
result = false
return
}
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
2017-05-14 00:36:32 +00:00
if !tmpE.FromBytes(&pubKey) {
result = false
return
}
2017-05-14 00:36:32 +00:00
var tmpPBytes, tmpEBytes Key
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 19:15:06 +00:00
tmpE = pubKey.HashToEC()
2017-05-05 03:11:50 +00:00
tmpE.ToBytes(&tmpEBytes)
2017-05-14 00:36:32 +00:00
GeDoubleScalarMultPrecompVartime(tmpP, rse.r, tmpE, rse.c, &keyImagePre)
2017-05-05 03:11:50 +00:00
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
2017-05-14 00:36:32 +00:00
ScAdd(sum, sum, rse.c)
2017-05-05 03:11:50 +00:00
}
2017-05-10 04:18:37 +00:00
tmpS = HashToScalar(toHash)
2017-05-14 00:36:32 +00:00
ScSub(sum, tmpS, sum)
result = ScIsZero(sum)
2017-05-05 03:11:50 +00:00
return
}