-
Notifications
You must be signed in to change notification settings - Fork 0
/
chest.go
86 lines (75 loc) · 2.16 KB
/
chest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package timelock
import (
"io"
"math/big"
tz "github.com/ecadlabs/gotez/v2"
"golang.org/x/crypto/nacl/secretbox"
)
type Chest struct {
LockedValue tz.BigUint `json:"locked_value"`
CipherText CipherText `json:"ciphertext"`
}
type CipherText struct {
Nonce [24]byte `json:"nonce"`
Payload []byte `tz:"dyn" json:"payload"`
}
type ChestKey = TimelockProof
func Encrypt(random io.Reader, key *[32]byte, payload []byte) (*CipherText, error) {
var nonce [24]byte
if _, err := io.ReadFull(random, nonce[:]); err != nil {
return nil, err
}
text := secretbox.Seal(nil, payload, &nonce, key)
return &CipherText{
Payload: text,
Nonce: nonce,
}, nil
}
func Decrypt(key *[32]byte, c *CipherText) ([]byte, bool) {
return secretbox.Open(nil, c.Payload, &c.Nonce, key)
}
func NewChest(random io.Reader, payload []byte, time int, mod *big.Int) (chest *Chest, key *ChestKey, err error) {
if time <= 0 {
return nil, nil, ErrInvalidArgument
}
vdfTuple, err := PrecomputeTimelock(random, time, mod)
if err != nil {
return nil, nil, err
}
return NewChestFromTimelock(random, payload, time, vdfTuple, mod)
}
func NewChestFromTimelock(random io.Reader, payload []byte, time int, timelock *Timelock, mod *big.Int) (chest *Chest, key *ChestKey, err error) {
if time <= 0 {
return nil, nil, ErrInvalidArgument
}
lockedValue, proof, err := timelock.NewProof(random, time, mod)
if err != nil {
return nil, nil, err
}
symKey := proof.SymmetricKey(mod)
cipherText, err := Encrypt(random, &symKey, payload)
if err != nil {
return nil, nil, err
}
return &Chest{
LockedValue: newBigUintUnsafe(lockedValue),
CipherText: *cipherText,
}, proof, nil
}
func (chest *Chest) NewKey(time int, mod *big.Int) (key *ChestKey, err error) {
if time <= 0 {
return nil, ErrInvalidArgument
}
return UnlockAndProve(time, chest.LockedValue.Int(), mod), nil
}
func (chest *Chest) Open(key *ChestKey, time int, mod *big.Int) ([]byte, bool, error) {
if time <= 0 {
return nil, false, ErrInvalidArgument
}
if !Verify(chest.LockedValue.Int(), key, time, mod) {
return nil, false, nil
}
symKey := key.SymmetricKey(mod)
out, ok := Decrypt(&symKey, &chest.CipherText)
return out, ok, nil
}