185 lines
4.7 KiB
Go
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
|
|
}
|