signing operation works. PoC quality
This commit is contained in:
parent
27d2fbe804
commit
98f1e7ef3d
@ -34,6 +34,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var be = binary.BigEndian
|
||||||
|
|
||||||
type Input struct {
|
type Input struct {
|
||||||
Operation string `json:"operation"`
|
Operation string `json:"operation"`
|
||||||
Arguments struct {
|
Arguments struct {
|
||||||
@ -106,15 +108,12 @@ func (ep *EdDSAPublicKey) MarshalJSON() ([]byte, error) {
|
|||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const CURRENCY_LEN = 12
|
||||||
CURRENCY_LEN = 12
|
|
||||||
CURRENCY_LEN_STR = "12"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Amount struct {
|
type Amount struct {
|
||||||
Value uint64 `json:"value"`
|
Value uint64 `json:"value"`
|
||||||
Fraction uint32 `json:"fraction"`
|
Fraction uint32 `json:"fraction"`
|
||||||
Currency string `json:"currency"`
|
Currency [CURRENCY_LEN]byte `json:"currency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amount comes in as something like "CHF:0.32"
|
// Amount comes in as something like "CHF:0.32"
|
||||||
@ -129,7 +128,7 @@ func (a *Amount) UnmarshalJSON(in []byte) (e error) {
|
|||||||
} else if len(parts[0]) >= CURRENCY_LEN || nonAllowedCharsRX.Match(parts[0]) {
|
} else if len(parts[0]) >= CURRENCY_LEN || nonAllowedCharsRX.Match(parts[0]) {
|
||||||
return fmt.Errorf("invalid currency")
|
return fmt.Errorf("invalid currency")
|
||||||
}
|
}
|
||||||
a.Currency = string(parts[0])
|
copy(a.Currency[:], parts[0][:])
|
||||||
|
|
||||||
// split and parse Value
|
// split and parse Value
|
||||||
parts = bytes.Split(parts[1], []byte("."))
|
parts = bytes.Split(parts[1], []byte("."))
|
||||||
@ -145,16 +144,47 @@ func (a *Amount) UnmarshalJSON(in []byte) (e error) {
|
|||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
if len(parts[1]) == 0 || len(parts[1]) > 8 {
|
if len(parts[1]) == 0 || len(parts[1]) > 8 {
|
||||||
return fmt.Errorf("invalid fraction")
|
return fmt.Errorf("invalid fraction")
|
||||||
} else if v, e := strconv.ParseUint(string(parts[1]), 10, 32); e != nil {
|
} else if a.Fraction, e = parseFraction(parts[1]); e != nil {
|
||||||
return e
|
return e
|
||||||
} else {
|
|
||||||
a.Fraction = uint32(v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// following exchange/src/util/amount.c TALER_string_to_amount()
|
||||||
|
func parseFraction(input []byte) (uint32, error) {
|
||||||
|
const TALER_AMOUNT_FRAC_BASE = 100_000_000
|
||||||
|
|
||||||
|
b := uint32(TALER_AMOUNT_FRAC_BASE / 10)
|
||||||
|
|
||||||
|
var f uint32
|
||||||
|
|
||||||
|
for _, c := range input {
|
||||||
|
if b == 0 {
|
||||||
|
return 0, fmt.Errorf("fractional value too small")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
return 0, fmt.Errorf("invalid fractional value")
|
||||||
|
}
|
||||||
|
|
||||||
|
f += uint32(c-'0') * b
|
||||||
|
b /= 10
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Amount) Binary() []byte {
|
||||||
|
buf := make([]byte, 8+4+CURRENCY_LEN)
|
||||||
|
be.PutUint64(buf, a.Value)
|
||||||
|
be.PutUint32(buf[8:], a.Fraction)
|
||||||
|
copy(buf[8+4:], a.Currency[:CURRENCY_LEN])
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
type EdDSASignature struct {
|
type EdDSASignature struct {
|
||||||
R []byte `json:"r"`
|
R []byte `json:"r"`
|
||||||
S []byte `json:"s"`
|
S []byte `json:"s"`
|
||||||
@ -399,10 +429,10 @@ type SignOperation struct {
|
|||||||
} `json:"arguments"`
|
} `json:"arguments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SHA512Hash []byte
|
type SHA512Hash [sha512.Size]byte
|
||||||
|
|
||||||
func (h *SHA512Hash) MarshalJSON() ([]byte, error) {
|
func (h *SHA512Hash) MarshalJSON() ([]byte, error) {
|
||||||
enc, err := crockfordEncode(*h)
|
enc, err := crockfordEncode((*h)[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error encoding %v: %e\n", h, err)
|
return nil, fmt.Errorf("error encoding %v: %e\n", h, err)
|
||||||
}
|
}
|
||||||
@ -415,7 +445,95 @@ func (h *SHA512Hash) MarshalJSON() ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyfile = flag.String("key", "", "filename of EC25519 private key")
|
func auditorSignDenom(denom *DenomKey, ahash SHA512Hash, master *EdDSAPublicKey, pk *ed25519.PrivateKey) (SHA512Hash, EdDSASignature) {
|
||||||
|
|
||||||
|
const TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS = 1064
|
||||||
|
|
||||||
|
/*
|
||||||
|
We write a bigendian encoded version of ExchangeKeyValidityPS.
|
||||||
|
|
||||||
|
type Purpose uint32
|
||||||
|
type ExchangeKeyValidityPS struct {
|
||||||
|
size uint32
|
||||||
|
purpose Purpose
|
||||||
|
auditor_url_hash SHA512Hash
|
||||||
|
master EdDSAPublicKey
|
||||||
|
start AbsoluteTime
|
||||||
|
expireWithdraw AbsoluteTime
|
||||||
|
expireDeposit AbsoluteTime
|
||||||
|
expireLegal AbsoluteTime
|
||||||
|
value Amount
|
||||||
|
feeWithdraw Amount
|
||||||
|
feeDeposit Amount
|
||||||
|
feeRefresh Amount
|
||||||
|
feeRefund Amount
|
||||||
|
denomHash SHA512Hash
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
size := 4 + // size
|
||||||
|
4 + // purpose
|
||||||
|
sha512.Size + // auditor_url_hash
|
||||||
|
ed25519.PublicKeySize + // master
|
||||||
|
4*8 + // start and expire*
|
||||||
|
5*(8+4+len(denom.Value.Currency)) + // value and fee*
|
||||||
|
sha512.Size // denomHash
|
||||||
|
buf := make([]byte, size)
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
be.PutUint32(buf[n:], uint32(size))
|
||||||
|
n += 4
|
||||||
|
be.PutUint32(buf[n:], TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS)
|
||||||
|
n += 4
|
||||||
|
copy(buf[n:], ahash[:])
|
||||||
|
n += len(ahash)
|
||||||
|
copy(buf[n:], *master)
|
||||||
|
n += len(*master)
|
||||||
|
for _, v := range []uint64{
|
||||||
|
denom.StampStart.TMs,
|
||||||
|
denom.StampExpireWithdraw.TMs,
|
||||||
|
denom.StampExpireDeposit.TMs,
|
||||||
|
denom.StampExpireLegal.TMs,
|
||||||
|
} {
|
||||||
|
be.PutUint64(buf[n:], v*1000) // milli -> micro
|
||||||
|
n += 8
|
||||||
|
}
|
||||||
|
for _, v := range [][]byte{
|
||||||
|
denom.Value.Binary(),
|
||||||
|
denom.FeeWithdraw.Binary(),
|
||||||
|
denom.FeeDeposit.Binary(),
|
||||||
|
denom.FeeRefresh.Binary(),
|
||||||
|
denom.FeeRefund.Binary(),
|
||||||
|
} {
|
||||||
|
copy(buf[n:], v)
|
||||||
|
n += len(v)
|
||||||
|
}
|
||||||
|
bin := denom.DenomPub.Binary()
|
||||||
|
hash := sha512.Sum512(bin)
|
||||||
|
copy(buf[n:], hash[:])
|
||||||
|
|
||||||
|
sig := ed25519.Sign(*pk, buf)
|
||||||
|
return hash, EdDSASignature{R: sig[:32], S: sig[32:]}
|
||||||
|
}
|
||||||
|
|
||||||
|
func auditorSign(input *Input, url string, pk ed25519.PrivateKey) []SignOperation {
|
||||||
|
|
||||||
|
output := make([]SignOperation, len(input.Arguments.Denoms))
|
||||||
|
for i, denom := range input.Arguments.Denoms {
|
||||||
|
output[i].Operation = "auditor-sign-denomination-0"
|
||||||
|
|
||||||
|
hash, sig := auditorSignDenom(&denom, sha512.Sum512(append([]byte(url), 0)), &input.Arguments.MasterPublicKey, &pk)
|
||||||
|
output[i].Arguments.HDenumPub = hash
|
||||||
|
output[i].Arguments.AuditorSig = sig
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
keyfile = flag.String("key", "auditor.key", "filename of EC25519 private key")
|
||||||
|
url = flag.String("url", "https://auditor.codeblau.de/", "auditor url")
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
@ -441,18 +559,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: here needs to go the call to TALER_exchange_offline_denom_validity_verify
|
// TODO: here needs to go the call to TALER_exchange_offline_denom_validity_verify
|
||||||
|
output := auditorSign(input, *url, pk)
|
||||||
output := make([]SignOperation, len(input.Arguments.Denoms))
|
|
||||||
for i, denom := range input.Arguments.Denoms {
|
|
||||||
output[i].Operation = "auditor-sign-denomination-0"
|
|
||||||
bin := denom.DenomPub.Binary()
|
|
||||||
sum := sha512.Sum512(bin)
|
|
||||||
output[i].Arguments.HDenumPub = sum[:]
|
|
||||||
|
|
||||||
// TODO: here needs to go the call to TALER_auditor_denom_validity_sign
|
|
||||||
sig := ed25519.Sign(pk, sum[:])
|
|
||||||
output[i].Arguments.AuditorSig = EdDSASignature{R: sig[:32], S: sig[32:]}
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(os.Stdout)
|
enc := json.NewEncoder(os.Stdout)
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
|
Loading…
Reference in New Issue
Block a user