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
2017-05-13 17:36:32 -07:00

185 lines
4.7 KiB
Go

package moneroutil
import (
"fmt"
"io"
"math/rand"
)
type RingSignatureElement struct {
c *Key
r *Key
}
type RingSignature []*RingSignatureElement
func (r *RingSignatureElement) Serialize() (result []byte) {
result = make([]byte, 2*KeyLength)
copy(result[:KeyLength], r.c[:])
copy(result[KeyLength:2*KeyLength], r.r[:])
return
}
func (r *RingSignature) Serialize() (result []byte) {
result = make([]byte, len(*r)*KeyLength*2)
for i := 0; i < len(*r); i++ {
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),
}
return
}
func ParseSignature(buf io.Reader) (result *RingSignatureElement, err error) {
rse := NewRingSignatureElement()
c := make([]byte, KeyLength)
n, err := buf.Read(c)
if err != nil {
return
}
if n != KeyLength {
err = fmt.Errorf("Not enough bytes for signature c")
return
}
copy(rse.c[:], c)
r := make([]byte, KeyLength)
n, err = buf.Read(r)
if err != nil {
return
}
if n != KeyLength {
err = fmt.Errorf("Not enough bytes for signature r")
return
}
copy(rse.r[:], r)
result = rse
return
}
func ParseSignatures(mixinLengths []int, buf io.Reader) (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
}
func HashToScalar(data ...[]byte) (result *Key) {
result = new(Key)
*result = Key(Keccak256(data...))
ScReduce32(result)
return
}
func CreateSignature(prefixHash *Hash, mixins []Key, privKey *Key) (keyImage Key, pubKeys []Key, sig RingSignature) {
point := privKey.PubKey().HashToEC()
keyImagePoint := new(ProjectiveGroupElement)
GeScalarMult(keyImagePoint, privKey, point)
// convert key Image point from Projective to Extended
// in order to precompute
keyImagePoint.ToBytes(&keyImage)
keyImageGe := new(ExtendedGroupElement)
keyImageGe.FromBytes(&keyImage)
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
k := RandomScalar()
pubKeys = make([]Key, len(mixins)+1)
privIndex := rand.Intn(len(pubKeys))
pubKeys[privIndex] = *privKey.PubKey()
r := make([]*RingSignatureElement, len(pubKeys))
sum := new(Key)
toHash := prefixHash[:]
for i := 0; i < len(pubKeys); i++ {
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
var tmpEBytes, tmpPBytes Key
if i == privIndex {
GeScalarMultBase(tmpE, k)
tmpE.ToBytes(&tmpEBytes)
toHash = append(toHash, tmpEBytes[:]...)
tmpE = privKey.PubKey().HashToEC()
GeScalarMult(tmpP, k, tmpE)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
} else {
if i > privIndex {
pubKeys[i] = mixins[i-1]
} else {
pubKeys[i] = mixins[i]
}
r[i] = &RingSignatureElement{
c: RandomScalar(),
r: RandomScalar(),
}
tmpE.FromBytes(&pubKeys[i])
GeDoubleScalarMultVartime(tmpP, r[i].c, tmpE, r[i].r)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
tmpE = pubKeys[i].HashToEC()
GeDoubleScalarMultPrecompVartime(tmpP, r[i].r, tmpE, r[i].c, &keyImagePre)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(sum, sum, r[i].c)
}
}
h := HashToScalar(toHash)
r[privIndex] = NewRingSignatureElement()
ScSub(r[privIndex].c, h, sum)
ScMulSub(r[privIndex].r, r[privIndex].c, privKey, k)
sig = r
return
}
func VerifySignature(prefixHash *Hash, keyImage *Key, pubKeys []Key, ringSignature RingSignature) (result bool) {
keyImageGe := new(ExtendedGroupElement)
if !keyImageGe.FromBytes(keyImage) {
result = false
return
}
var keyImagePre [8]CachedGroupElement
GePrecompute(&keyImagePre, keyImageGe)
toHash := prefixHash[:]
tmpS, sum := new(Key), new(Key)
for i, pubKey := range pubKeys {
rse := ringSignature[i]
if !ScValid(rse.c) || !ScValid(rse.r) {
result = false
return
}
tmpE := new(ExtendedGroupElement)
tmpP := new(ProjectiveGroupElement)
if !tmpE.FromBytes(&pubKey) {
result = false
return
}
var tmpPBytes, tmpEBytes Key
GeDoubleScalarMultVartime(tmpP, rse.c, tmpE, rse.r)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
tmpE = pubKey.HashToEC()
tmpE.ToBytes(&tmpEBytes)
GeDoubleScalarMultPrecompVartime(tmpP, rse.r, tmpE, rse.c, &keyImagePre)
tmpP.ToBytes(&tmpPBytes)
toHash = append(toHash, tmpPBytes[:]...)
ScAdd(sum, sum, rse.c)
}
tmpS = HashToScalar(toHash)
ScSub(sum, tmpS, sum)
result = ScIsZero(sum)
return
}