...
This commit is contained in:
@@ -3,6 +3,7 @@ module giteaclient
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import json
|
||||
|
||||
__global (
|
||||
giteaclient_global map[string]&GiteaClient
|
||||
@@ -31,10 +32,14 @@ pub fn get(args ArgsGet) !&GiteaClient {
|
||||
mut context := base.context()!
|
||||
giteaclient_default = args.name
|
||||
if args.fromdb || args.name !in giteaclient_global {
|
||||
if context.hero_config_exists('giteaclient', args.name) {
|
||||
heroscript := context.hero_config_get('giteaclient', args.name)!
|
||||
mut obj_ := heroscript_loads(heroscript)!
|
||||
set_in_mem(obj_)!
|
||||
mut r := context.redis()!
|
||||
if r.hexists('context:giteaclient', args.name)! {
|
||||
data := r.hget('context:giteaclient', args.name)!
|
||||
if data.len == 0 {
|
||||
return error('giteaclient with name:${args.name} does not exist, prob bug.')
|
||||
}
|
||||
mut obj := json.decode(GiteaClient,data)!
|
||||
set_in_mem(obj)!
|
||||
}else{
|
||||
if args.create {
|
||||
new(args)!
|
||||
@@ -54,20 +59,22 @@ pub fn set(o GiteaClient) ! {
|
||||
set_in_mem(o)!
|
||||
giteaclient_default = o.name
|
||||
mut context := base.context()!
|
||||
heroscript := heroscript_dumps(o)!
|
||||
context.hero_config_set('giteaclient', o.name, heroscript)!
|
||||
mut r := context.redis()!
|
||||
r.hset('context:giteaclient', o.name, json.encode(o))!
|
||||
}
|
||||
|
||||
// does the config exists?
|
||||
pub fn exists(args ArgsGet) !bool {
|
||||
mut context := base.context()!
|
||||
return context.hero_config_exists('giteaclient', args.name)
|
||||
mut r := context.redis()!
|
||||
return r.hexists('context:giteaclient', args.name)!
|
||||
|
||||
}
|
||||
|
||||
pub fn delete(args ArgsGet) ! {
|
||||
mut context := base.context()!
|
||||
giteaclient_global.delete(args.name)
|
||||
context.hero_config_delete('giteaclient', args.name)!
|
||||
mut r := context.redis()!
|
||||
r.hdel('context:giteaclient', args.name)!
|
||||
}
|
||||
|
||||
@[params]
|
||||
@@ -86,11 +93,11 @@ pub fn list(args ArgsList) ![]&GiteaClient {
|
||||
giteaclient_default = ''
|
||||
}
|
||||
if args.fromdb {
|
||||
for name in context.hero_config_list('giteaclient')!{
|
||||
mut hscript := context.hero_config_get('giteaclient', name)!
|
||||
mut obj := heroscript_loads(hscript)!
|
||||
set_in_mem(obj)!
|
||||
res << &obj
|
||||
mut r := context.redis()!
|
||||
mut l := r.hkeys('context:giteaclient')!
|
||||
|
||||
for name in l{
|
||||
res << get(name:name,fromdb:true)!
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
|
||||
@@ -57,13 +57,4 @@ fn obj_init(mycfg_ GiteaClient) !GiteaClient {
|
||||
return mycfg
|
||||
}
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj GiteaClient) !string {
|
||||
return encoderhero.encode[GiteaClient](obj)!
|
||||
}
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !GiteaClient {
|
||||
mut obj := encoderhero.decode[GiteaClient](heroscript)!
|
||||
return obj
|
||||
}
|
||||
pub
|
||||
@@ -2,23 +2,14 @@ module base
|
||||
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
import freeflowuniverse.herolib.core.redisclient
|
||||
import freeflowuniverse.herolib.data.dbfs
|
||||
import freeflowuniverse.herolib.crypt.aes_symmetric
|
||||
import freeflowuniverse.herolib.ui
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.core.rootpath
|
||||
import json
|
||||
import os
|
||||
import crypto.md5
|
||||
|
||||
@[heap]
|
||||
pub struct Context {
|
||||
mut:
|
||||
// priv_key_ ?&secp256k1.Secp256k1 @[skip; str: skip]
|
||||
params_ ?¶msparser.Params
|
||||
dbcollection_ ?&dbfs.DBCollection @[skip; str: skip]
|
||||
redis_ ?&redisclient.Redis @[skip; str: skip]
|
||||
path_ ?pathlib.Path
|
||||
pub mut:
|
||||
@@ -34,10 +25,10 @@ pub mut:
|
||||
params string
|
||||
coderoot string
|
||||
interactive bool
|
||||
secret string // is hashed secret
|
||||
priv_key string // encrypted version
|
||||
db_path string // path to dbcollection
|
||||
encrypt bool
|
||||
// secret string // is hashed secret
|
||||
// priv_key string // encrypted version
|
||||
// db_path string // path to dbcollection
|
||||
// encrypt bool
|
||||
}
|
||||
|
||||
// return the gistructure as is being used in context
|
||||
@@ -97,105 +88,44 @@ fn (mut self Context) cfg_redis_exists() !bool {
|
||||
return r.exists('context:config')!
|
||||
}
|
||||
|
||||
// return db collection
|
||||
pub fn (mut self Context) dbcollection() !&dbfs.DBCollection {
|
||||
mut dbc2 := self.dbcollection_ or {
|
||||
if self.config.db_path.len == 0 {
|
||||
self.config.db_path = '${os.home_dir()}/hero/db/${self.config.id}'
|
||||
}
|
||||
mut dbc := dbfs.get(
|
||||
contextid: self.config.id
|
||||
dbpath: self.config.db_path
|
||||
secret: self.config.secret
|
||||
)!
|
||||
self.dbcollection_ = &dbc
|
||||
&dbc
|
||||
}
|
||||
|
||||
return dbc2
|
||||
}
|
||||
|
||||
pub fn (mut self Context) db_get(dbname string) !dbfs.DB {
|
||||
mut dbc := self.dbcollection()!
|
||||
return dbc.db_get_create(name: dbname, withkeys: true)!
|
||||
}
|
||||
|
||||
// always return the config db which is the same for all apps in context
|
||||
pub fn (mut self Context) db_config_get() !dbfs.DB {
|
||||
mut dbc := self.dbcollection()!
|
||||
return dbc.db_get_create(name: 'config', withkeys: true)!
|
||||
}
|
||||
|
||||
// pub fn (mut self Context) hero_config_set(cat string, name string, content_ string) ! {
|
||||
// mut content := texttools.dedent(content_)
|
||||
// content = rootpath.shell_expansion(content)
|
||||
// path := '${self.path()!.path}/${cat}/${name}.json'
|
||||
// mut config_file := pathlib.get_file(path: path,create: true)!
|
||||
// config_file.write(content)!
|
||||
// pub fn (mut self Context) secret_encrypt(txt string) !string {
|
||||
// return aes_symmetric.encrypt_str(txt, self.secret_get()!)
|
||||
// }
|
||||
|
||||
// pub fn (mut self Context) hero_config_delete(cat string, name string) ! {
|
||||
// path := '${self.path()!.path}/${cat}/${name}.json'
|
||||
// mut config_file := pathlib.get_file(path: path)!
|
||||
// config_file.delete()!
|
||||
// pub fn (mut self Context) secret_decrypt(txt string) !string {
|
||||
// return aes_symmetric.decrypt_str(txt, self.secret_get()!)
|
||||
// }
|
||||
|
||||
// pub fn (mut self Context) hero_config_exists(cat string, name string) bool {
|
||||
// path := '${os.home_dir()}/hero/context/${self.config.name}/${cat}/${name}.json'
|
||||
// return os.exists(path)
|
||||
// pub fn (mut self Context) secret_get() !string {
|
||||
// mut secret := self.config.secret
|
||||
// if secret == '' {
|
||||
// self.secret_configure()!
|
||||
// secret = self.config.secret
|
||||
// self.save()!
|
||||
// }
|
||||
// if secret == '' {
|
||||
// return error("can't get secret")
|
||||
// }
|
||||
// return secret
|
||||
// }
|
||||
|
||||
// pub fn (mut self Context) hero_config_get(cat string, name string) !string {
|
||||
// path := '${self.path()!.path}/${cat}/${name}.json'
|
||||
// mut config_file := pathlib.get_file(path: path, create: false)!
|
||||
// return config_file.read()!
|
||||
// // show a UI in console to configure the secret
|
||||
// pub fn (mut self Context) secret_configure() ! {
|
||||
// mut myui := ui.new()!
|
||||
// console.clear()
|
||||
// secret_ := myui.ask_question(question: 'Please enter your hero secret string:')!
|
||||
// self.secret_set(secret_)!
|
||||
// }
|
||||
|
||||
// pub fn (mut self Context) hero_config_list(cat string) ![]string {
|
||||
// path := '${self.path()!.path}/${cat}'
|
||||
// mut config_files := os.ls(path)!
|
||||
// config_files = config_files.filter(it.ends_with('.json').map(it.split('.')[0] or {panic("bug")})
|
||||
// return config_files
|
||||
// // unhashed secret
|
||||
// pub fn (mut self Context) secret_set(secret_ string) ! {
|
||||
// secret := secret_.trim_space()
|
||||
// secret2 := md5.hexhash(secret)
|
||||
// self.config.secret = secret2
|
||||
// self.save()!
|
||||
// }
|
||||
|
||||
|
||||
pub fn (mut self Context) secret_encrypt(txt string) !string {
|
||||
return aes_symmetric.encrypt_str(txt, self.secret_get()!)
|
||||
}
|
||||
|
||||
pub fn (mut self Context) secret_decrypt(txt string) !string {
|
||||
return aes_symmetric.decrypt_str(txt, self.secret_get()!)
|
||||
}
|
||||
|
||||
pub fn (mut self Context) secret_get() !string {
|
||||
mut secret := self.config.secret
|
||||
if secret == '' {
|
||||
self.secret_configure()!
|
||||
secret = self.config.secret
|
||||
self.save()!
|
||||
}
|
||||
if secret == '' {
|
||||
return error("can't get secret")
|
||||
}
|
||||
return secret
|
||||
}
|
||||
|
||||
// show a UI in console to configure the secret
|
||||
pub fn (mut self Context) secret_configure() ! {
|
||||
mut myui := ui.new()!
|
||||
console.clear()
|
||||
secret_ := myui.ask_question(question: 'Please enter your hero secret string:')!
|
||||
self.secret_set(secret_)!
|
||||
}
|
||||
|
||||
// unhashed secret
|
||||
pub fn (mut self Context) secret_set(secret_ string) ! {
|
||||
secret := secret_.trim_space()
|
||||
secret2 := md5.hexhash(secret)
|
||||
self.config.secret = secret2
|
||||
self.save()!
|
||||
}
|
||||
|
||||
pub fn (mut self Context) path() !pathlib.Path {
|
||||
return self.path_ or {
|
||||
path2 := '${os.home_dir()}/hero/context/${self.config.name}'
|
||||
|
||||
@@ -36,30 +36,12 @@ pub fn context_new(args_ ContextConfigArgs) !&Context {
|
||||
params: args_.params
|
||||
coderoot: args_.coderoot
|
||||
interactive: args_.interactive
|
||||
secret: args_.secret
|
||||
encrypt: args_.encrypt
|
||||
}
|
||||
|
||||
if args.encrypt && args.secret == '' && args.interactive {
|
||||
mut myui := ui.new()!
|
||||
console.clear()
|
||||
args.secret = myui.ask_question(question: 'Please enter your hero secret string:')!
|
||||
}
|
||||
|
||||
if args.encrypt && args.secret.len > 0 {
|
||||
args.secret = md5.hexhash(args.secret)
|
||||
}
|
||||
|
||||
mut c := Context{
|
||||
config: args
|
||||
}
|
||||
|
||||
// if args_.priv_key_hex.len > 0 {
|
||||
// c.privkey_set(args_.priv_key_hex)!
|
||||
// }
|
||||
|
||||
// c.save()!
|
||||
|
||||
if args.params.len > 0 {
|
||||
mut p := paramsparser.new('')!
|
||||
c.params_ = &p
|
||||
|
||||
@@ -3,7 +3,6 @@ module base
|
||||
import freeflowuniverse.herolib.data.ourtime
|
||||
// import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.data.paramsparser
|
||||
import freeflowuniverse.herolib.data.dbfs
|
||||
import freeflowuniverse.herolib.core.logger
|
||||
import json
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
@@ -32,15 +31,6 @@ pub mut:
|
||||
// return 'hero:sessions:${self.guid()}'
|
||||
// }
|
||||
|
||||
// get db of the session, is unique per session
|
||||
pub fn (mut self Session) db_get() !dbfs.DB {
|
||||
return self.context.db_get('session_${self.name}')!
|
||||
}
|
||||
|
||||
// get the db of the config, is unique per context
|
||||
pub fn (mut self Session) db_config_get() !dbfs.DB {
|
||||
return self.context.db_get('config')!
|
||||
}
|
||||
|
||||
// load the params from redis
|
||||
pub fn (mut self Session) load() ! {
|
||||
|
||||
@@ -66,14 +66,3 @@ fn configure() ! {
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj ${args.classname}) !string {
|
||||
return encoderhero.encode[${args.classname} ](obj)!
|
||||
}
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !${args.classname} {
|
||||
mut obj := encoderhero.decode[${args.classname}](heroscript)!
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
# libsecp256k1
|
||||
|
||||
This is a lib256k1 binding for vlang.
|
||||
|
||||
## Requirements
|
||||
|
||||
make sure the lib is installed
|
||||
|
||||
### macOS
|
||||
|
||||
```bash
|
||||
brew install secp256k1
|
||||
```
|
||||
|
||||
### Ubuntu
|
||||
|
||||
Compile latest release, version included in Ubuntu is outdated.
|
||||
|
||||
```
|
||||
apt-get install -y build-essential wget autoconf libtool
|
||||
|
||||
wget https://github.com/bitcoin-core/secp256k1/archive/refs/tags/v0.3.2.tar.gz
|
||||
tar -xvf v0.3.2.tar.gz
|
||||
|
||||
cd secp256k1-0.3.2/
|
||||
./autogen.sh
|
||||
./configure
|
||||
make -j 5
|
||||
make install
|
||||
```
|
||||
|
||||
### Arch
|
||||
|
||||
```bash
|
||||
pacman -Su extra/libsecp256k1
|
||||
```
|
||||
|
||||
### Gentoo
|
||||
|
||||
```bash
|
||||
emerge dev-libs/libsecp256k1
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Generate EC keys
|
||||
- [x] Load existing EC keys
|
||||
- [x] Serialize keys
|
||||
- [x] Derivate shared key
|
||||
- [x] Sign using ECDSA
|
||||
- [x] Verify ECDSA signature
|
||||
- [x] Sign using Schnorr
|
||||
- [x] Verify a Schnorr signature
|
||||
- [ ] Support multi-signature with Schnorr
|
||||
|
||||
## How to use
|
||||
|
||||
There are 4 differents things / features to understand in this secp256k1 implementation (wrapper).
|
||||
|
||||
### Public and Privaye keys for secp256k1
|
||||
|
||||
This is a simple private/public key schema. This wrapper deals with hexdump of keys.
|
||||
|
||||
- Private key is `32 bytes` long (eg: `0x4a21f247ff3744e211e95ec478d5aba94a1d6d8bed613e8a9faece6d048399fc`)
|
||||
- Public key is `33 bytes` long (eg: `0x02df72fc4fa607ca3478446750bf9f8510242c4fa5849e77373d71104cd0c82ea0`)
|
||||
|
||||
In this library, you can instanciate a secp256k1 object from 3 ways:
|
||||
```vlang
|
||||
import freeflowuniverse.herolib.crypt.secp256k1
|
||||
secp256k1.new()
|
||||
```
|
||||
Constructor without any arguments, will generate a new private and public key
|
||||
|
||||
```vlang
|
||||
secp256k1.new(privkey: '0x4a21f247ff3744e211e95ec478d5aba94a1d6d8bed613e8a9faece6d048399fc')
|
||||
```
|
||||
Using `privkey` argument, this will create an object from private key and generate corresponding public key
|
||||
|
||||
```vlang
|
||||
secp256k1.new(pubkey: '0x02df72fc4fa607ca3478446750bf9f8510242c4fa5849e77373d71104cd0c82ea0')
|
||||
```
|
||||
Using `privkey` argument, this will create an object with only the public key,
|
||||
which can be used for shared key or signature verification
|
||||
|
||||
### Shared Keys
|
||||
|
||||
Library `secp256k1` have one feature which allows you to derivate a `shared intermediate common key` from
|
||||
the private key of one party and the public key from the other party.
|
||||
|
||||
Example:
|
||||
- Shared key from `Bob Private Key` + `Alice Public Key` = `Shared Key`
|
||||
- Shared key from `Alice Private Key` + `Bob Public Key` = `Shared Key` (the same)
|
||||
|
||||
Using this feature, with your private key and target public key, you can derivate a `shared (secret) key`
|
||||
that only you both knows. This is really interresting to switch to a symetric encryption using that key
|
||||
as encryption key or use any well known secret without exchanging it.
|
||||
|
||||
To use the shared key feature, just call the `sharedkeys()` method:
|
||||
```vlang
|
||||
bob := secp256k1.new(privhex: '0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83')!
|
||||
alicepub := secp256k1.new(pubkey: '0x034a87ad6fbf83d89a91c257d4cc038828c6ed9104738ffd4bb7e5069858d4767b')!
|
||||
|
||||
shared := bob.sharedkeys(alicepub)
|
||||
// shared = 0xf114df29d930f0cd37f62cbca36c46773a42bf87e12edcb35d47c4bfbd20514d
|
||||
```
|
||||
|
||||
This works the same in the opposite direction:
|
||||
```vlang
|
||||
alice := secp256k1.new(privhex: '0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec')!
|
||||
bobpub := secp256k1.new(pubkey: '0x03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21')!
|
||||
|
||||
shared := alice.sharedkeys(bobpub)
|
||||
// shared = 0xf114df29d930f0cd37f62cbca36c46773a42bf87e12edcb35d47c4bfbd20514d (same shared key)
|
||||
```
|
||||
|
||||
### ECDSA Signature
|
||||
|
||||
This is the default signature method. When doing a signature, you don't sign the actual data but you
|
||||
have to sign a hash (sha256) of the data. This payload needs to be fixed length. The return signature
|
||||
is a `64 bytes` long response.
|
||||
|
||||
When doing a signature using ecdsa method, you sign using the private key and verify using the public key
|
||||
of the same party. If **Bob** sign something, you have to verify using **Bob** public key is the signature matches.
|
||||
|
||||
If signature matches, that mean that is really **Bob** who signed the hash.
|
||||
Here, you need the signature and the message separately.
|
||||
|
||||
```vlang
|
||||
sstr := alice.sign_str("Hello World !")
|
||||
valid := alicepub.verify_str(sstr, "Hello World !")
|
||||
// valid = true
|
||||
```
|
||||
|
||||
### Schnorr Signature
|
||||
|
||||
This is the new prefered signature method. In theory, this method can in addition be able to sign
|
||||
using multiple parties without storing signature of everyone, signature can be chained but this is not
|
||||
implemented in this wrapper (lack of source documentation and understanding).
|
||||
|
||||
In practice, code wide, wrapper take care to handle everything for you and this really looks like
|
||||
the same way than ecdsa.
|
||||
|
||||
```vlang
|
||||
schnorr_sstr := alice.schnorr_sign_str("Hello World !")
|
||||
valid := alicepub.schnorr_verify_str(schnorr_sstr, "Hello World !")
|
||||
// valid = true
|
||||
```
|
||||
@@ -1,351 +0,0 @@
|
||||
@[translated]
|
||||
module secp256k1
|
||||
|
||||
import encoding.hex
|
||||
import crypto.sha256
|
||||
import encoding.base64
|
||||
|
||||
#include "@VMODROOT/secp256k1mod.h"
|
||||
|
||||
#flag @VMODROOT/secp256k1mod.o
|
||||
#flag -lsecp256k1
|
||||
#flag -DNO_SECP_MAIN
|
||||
#flag darwin -I/opt/homebrew/include
|
||||
#flag darwin -L/opt/homebrew/lib
|
||||
|
||||
// linux: require libsecp256k1-dev
|
||||
// macos: require brew install secp256k1
|
||||
|
||||
//
|
||||
// struct definitions
|
||||
//
|
||||
struct Secp256k1_pubkey {
|
||||
data [64]u8
|
||||
}
|
||||
|
||||
struct Secp256k1_xonly_pubkey {
|
||||
data [64]u8
|
||||
}
|
||||
|
||||
struct Secp256k1_ecdsa_signature {
|
||||
data [64]u8
|
||||
}
|
||||
|
||||
struct Secp256k1_keypair {
|
||||
data [96]u8
|
||||
}
|
||||
|
||||
struct Secp256k1_t {
|
||||
kntxt &C.secp256k1_context
|
||||
seckey &u8
|
||||
compressed &u8
|
||||
pubkey Secp256k1_pubkey
|
||||
xcompressed &u8
|
||||
xpubkey Secp256k1_xonly_pubkey
|
||||
keypair Secp256k1_keypair
|
||||
}
|
||||
|
||||
struct Secp256k1_sign_t {
|
||||
sig Secp256k1_ecdsa_signature
|
||||
serialized &u8
|
||||
length usize
|
||||
}
|
||||
|
||||
struct Secp256k1_signature {
|
||||
cctx &C.secp256k1_sign_t
|
||||
}
|
||||
|
||||
pub struct Secp256k1 {
|
||||
cctx &Secp256k1_t
|
||||
}
|
||||
|
||||
//
|
||||
// prototypes
|
||||
//
|
||||
fn C.secp256k1_new() &Secp256k1_t
|
||||
|
||||
fn C.secp256k1_schnorr_verify(secp &Secp256k1_t, signature &u8, siglen usize, hash &u8, hashlen usize) int
|
||||
|
||||
fn C.secp256k1_schnorr_sign_hash(secp &Secp256k1_t, hash &u8, length usize) &u8
|
||||
|
||||
fn C.secp256k1_sign_verify(secp &Secp256k1_t, signature &Secp256k1_sign_t, hash &u8, length usize) int
|
||||
|
||||
fn C.secp256k1_sign_free(signature &Secp256k1_sign_t)
|
||||
|
||||
fn C.secp256k1_load_signature(secp &Secp256k1_t, serialized &u8, length usize) &Secp256k1_sign_t
|
||||
|
||||
fn C.secp256k1_sign_hash(secp &Secp256k1_t, hash &u8, length usize) &u8
|
||||
|
||||
fn C.secp265k1_shared_key(private &Secp256k1_t, public &Secp256k1_t) &u8
|
||||
|
||||
fn C.secp256k1_load_key(secp &Secp256k1_t, key &u8) int
|
||||
|
||||
fn C.secp256k1_load_private_key(secp &Secp256k1_t, key &u8) int
|
||||
|
||||
fn C.secp256k1_load_public_key(secp &Secp256k1_t, key &u8) int
|
||||
|
||||
fn C.secp256k1_free(secp &Secp256k1_t)
|
||||
|
||||
fn C.secp256k1_dumps(secp &Secp256k1_t)
|
||||
|
||||
fn C.secp256k1_export(secp &Secp256k1_t) &u8
|
||||
|
||||
fn C.secp256k1_private_key(secp &Secp256k1_t) &u8
|
||||
|
||||
fn C.secp256k1_public_key(secp &Secp256k1_t) &u8
|
||||
|
||||
fn C.secp256k1_generate_key(secp &Secp256k1_t) int
|
||||
|
||||
@[params]
|
||||
pub struct Secp256NewArgs {
|
||||
pub:
|
||||
pubhex string // public key hex (eg 03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21)
|
||||
privhex string // private key hex (eg 478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83)
|
||||
pubbase64 string
|
||||
privbase64 string
|
||||
// key []u8 // is in binary form (not implemented)
|
||||
}
|
||||
|
||||
// get a Secp256k1 key, can start from an existing key in string hex format (starts with 0x)
|
||||
// parameters:
|
||||
// privhex: private key in hex format (full features will be available)
|
||||
// pubhex: public key in hex format (reduced features available)
|
||||
//
|
||||
// keyhex string // e.g. 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||
// // keyhex is still supported for _backward_ compatibility only, please do not use anymore
|
||||
//
|
||||
// key []u8 // is in binary form (not implemented)
|
||||
// generate bool = true // default will generate a new key .
|
||||
pub fn new(args_ Secp256NewArgs) !Secp256k1 {
|
||||
mut args := args_
|
||||
|
||||
secp := Secp256k1{}
|
||||
secp.cctx = C.secp256k1_new()
|
||||
|
||||
// if args.key.len > 0 && args.privhex.len > 0 {
|
||||
// return error('cannot specify privhex and key at same time')
|
||||
// }
|
||||
|
||||
if args.privhex.len > 0 && args.pubhex.len > 0 {
|
||||
return error('cannot specify private and public key at same time')
|
||||
}
|
||||
if args.privhex.len > 0 {
|
||||
// same as keyhex (backward compatibility)
|
||||
// load key from hex like 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||
// key is the private key
|
||||
if !(args.privhex.starts_with('0x')) {
|
||||
args.privhex = '0x${args.privhex}'
|
||||
}
|
||||
load := C.secp256k1_load_private_key(secp.cctx, args.privhex.str)
|
||||
if load > 0 {
|
||||
return error('invalid private key')
|
||||
}
|
||||
} else if args.pubhex.len > 0 {
|
||||
// load key from hex like 0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83
|
||||
// key is the public key, this only allow signature check, shared keys, etc.
|
||||
if !(args.pubhex.starts_with('0x')) {
|
||||
args.pubhex = '0x${args.pubhex}'
|
||||
}
|
||||
load := C.secp256k1_load_public_key(secp.cctx, args.pubhex.str)
|
||||
if load > 0 {
|
||||
return error('invalid public key')
|
||||
}
|
||||
} else if args.privbase64.len > 0 {
|
||||
keybin := base64.decode(args.privbase64)
|
||||
keyhex := hex.encode(keybin)
|
||||
keyhex2 := '0x${keyhex}'
|
||||
return new(privhex: keyhex2)!
|
||||
} else if args.pubbase64.len > 0 {
|
||||
keybin := base64.decode(args.pubbase64)
|
||||
keyhex := hex.encode(keybin)
|
||||
keyhex2 := '0x${keyhex}'
|
||||
return new(pubhex: keyhex2)!
|
||||
} else {
|
||||
C.secp256k1_generate_key(secp.cctx)
|
||||
}
|
||||
|
||||
// TODO: implement the binary key input
|
||||
// TODO: check format in side and report properly
|
||||
|
||||
// dumps keys for debugging purpose
|
||||
// secp.keys()
|
||||
|
||||
return secp
|
||||
}
|
||||
|
||||
// request keys dump from low level library
|
||||
// this basically prints keys from internal objects (private, public, shared, x-only, ...)
|
||||
// warning: this is for debug purpose
|
||||
fn (s Secp256k1) keys() {
|
||||
C.secp256k1_dumps(s.cctx)
|
||||
}
|
||||
|
||||
// export private key
|
||||
// backward compatibility, please use private_key() and public_key() methods
|
||||
pub fn (s Secp256k1) export() string {
|
||||
key := C.secp256k1_export(s.cctx)
|
||||
return unsafe { key.vstring() }
|
||||
}
|
||||
|
||||
// with a private key in pair with a public key, secp256k1 can derivate a shared
|
||||
// key which is the same for both parties, this is really interresting to use for example
|
||||
// that shared keys for symetric encryption key since it's private but common
|
||||
//
|
||||
// example: sharedkey(bobpriv + alicepub) = abcdef
|
||||
// sharedkey(alicepriv + bobpub) = abcdef
|
||||
//
|
||||
// both parties can use their own private key with target public key to derivate the same
|
||||
// shared commun key, this key is unique with that pair.
|
||||
pub fn (s Secp256k1) sharedkeys(target Secp256k1) []u8 {
|
||||
shr := C.secp265k1_shared_key(s.cctx, target.cctx)
|
||||
return unsafe { shr.vbytes(32) } // 32 bytes shared key
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) sharedkeys_hex(target Secp256k1) string {
|
||||
keybin := s.sharedkeys(target)
|
||||
return hex.encode(keybin)
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) sharedkeys_base64(target Secp256k1) string {
|
||||
keybin := s.sharedkeys(target)
|
||||
return base64.encode(keybin)
|
||||
}
|
||||
|
||||
// returns private key in hex format
|
||||
pub fn (s Secp256k1) private_key_hex() string {
|
||||
key := C.secp256k1_private_key(s.cctx)
|
||||
return unsafe { key.vstring()[2..] }
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) private_key_base64() string {
|
||||
key := s.private_key_hex()
|
||||
keybin := hex.decode(key) or { panic("can't decode hex") }
|
||||
return base64.encode(keybin)
|
||||
}
|
||||
|
||||
// return public key in hex format
|
||||
pub fn (s Secp256k1) public_key_hex() string {
|
||||
key := C.secp256k1_public_key(s.cctx)
|
||||
return unsafe { key.vstring()[2..] }
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) public_key_base64() string {
|
||||
key := s.public_key_hex()
|
||||
keybin := hex.decode(key) or { panic("can't decode hex") }
|
||||
return base64.encode(keybin)
|
||||
}
|
||||
|
||||
//
|
||||
// sign (ecdsa) data
|
||||
// - we force user to pass data to ensure we hash the right way
|
||||
// data to ensure signature is valid and safe
|
||||
//
|
||||
pub fn (s Secp256k1) sign_data(data []u8) []u8 {
|
||||
// hash data
|
||||
h256 := sha256.sum(data)
|
||||
signature := C.secp256k1_sign_hash(s.cctx, h256.data, h256.len)
|
||||
|
||||
return unsafe { signature.vbytes(64) } // 64 bytes signature
|
||||
}
|
||||
|
||||
// return a hex string of the signature
|
||||
pub fn (s Secp256k1) sign_data_hex(data []u8) string {
|
||||
payload := s.sign_data(data)
|
||||
return hex.encode(payload)
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) sign_data_base64(data []u8) string {
|
||||
payload := s.sign_data(data)
|
||||
return base64.encode(payload)
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) sign_str(data string) []u8 {
|
||||
return s.sign_data(data.bytes())
|
||||
}
|
||||
|
||||
// return a hex string of the signature
|
||||
pub fn (s Secp256k1) sign_str_hex(data string) string {
|
||||
return s.sign_data_hex(data.bytes())
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) sign_str_base64(data string) string {
|
||||
payload := s.sign_data(data.bytes())
|
||||
return base64.encode(payload)
|
||||
}
|
||||
|
||||
//
|
||||
// verify a signature
|
||||
//
|
||||
pub fn (s Secp256k1) verify_data(signature []u8, data []u8) bool {
|
||||
// todo: check size signature
|
||||
sig := Secp256k1_signature{}
|
||||
sig.cctx = C.secp256k1_load_signature(s.cctx, signature.data, signature.len)
|
||||
|
||||
// compute data hash to ensure we do it correctly
|
||||
// - do not trust the user, do it ourself -
|
||||
h256 := sha256.sum(data)
|
||||
valid := C.secp256k1_sign_verify(s.cctx, sig.cctx, h256.data, h256.len)
|
||||
if valid == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) verify_str_base64(signature string, input string) bool {
|
||||
signature2 := base64.decode(signature)
|
||||
return s.verify_data(signature2, input.bytes())
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) verify_str_hex(signature string, input string) bool {
|
||||
signature2 := hex.decode(signature) or { panic("couldn't decode 64") }
|
||||
return s.verify_data(signature2, input.bytes())
|
||||
}
|
||||
|
||||
//
|
||||
// sign (schnorr) data
|
||||
// - we force user to pass data to ensure we hash the right way
|
||||
// data to ensure signature is valid and safe
|
||||
//
|
||||
pub fn (s Secp256k1) schnorr_sign_data(data []u8) []u8 {
|
||||
// hash data
|
||||
h256 := sha256.sum(data)
|
||||
signature := C.secp256k1_schnorr_sign_hash(s.cctx, h256.data, h256.len)
|
||||
|
||||
return unsafe { signature.vbytes(64) } // 64 bytes signature
|
||||
}
|
||||
|
||||
// return a hex string of the signature
|
||||
pub fn (s Secp256k1) schnorr_sign_data_hex(data []u8) string {
|
||||
payload := s.schnorr_sign_data(data)
|
||||
return hex.encode(payload)
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) schnorr_sign_str(data string) []u8 {
|
||||
return s.schnorr_sign_data(data.bytes())
|
||||
}
|
||||
|
||||
// return a hex string of the signature
|
||||
pub fn (s Secp256k1) schnorr_sign_str_hex(data string) string {
|
||||
return s.schnorr_sign_data_hex(data.bytes())
|
||||
}
|
||||
|
||||
//
|
||||
// verify a signature
|
||||
//
|
||||
pub fn (s Secp256k1) schnorr_verify_data(signature []u8, data []u8) bool {
|
||||
// compute data hash to ensure we do it correctly
|
||||
// - do not trust the user, do it ourself -
|
||||
h256 := sha256.sum(data)
|
||||
valid := C.secp256k1_schnorr_verify(s.cctx, signature.data, signature.len, h256.data,
|
||||
h256.len)
|
||||
if valid == 1 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (s Secp256k1) schnorr_verify_str(signature []u8, input string) bool {
|
||||
return s.schnorr_verify_data(signature, input.bytes())
|
||||
}
|
||||
@@ -1,460 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/random.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include "secp256k1mod.h"
|
||||
|
||||
static int fill_random(unsigned char* data, size_t size) {
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
ssize_t res = getrandom(data, size, 0);
|
||||
if(res < 0 || (size_t) res != size) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||
int res = getentropy(data, size);
|
||||
if(res == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dumphex(unsigned char *data, size_t size) {
|
||||
size_t i;
|
||||
|
||||
printf("0x");
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
printf("%02x", data[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static char *hexifier(unsigned char *data, size_t size) {
|
||||
char *target = calloc(sizeof(char), (size * 2) + 4);
|
||||
char buffer[8];
|
||||
|
||||
strcpy(target, "0x");
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
for(size_t i = 0; i < size; i++) {
|
||||
sprintf(buffer, "%02x", data[i]);
|
||||
strcat(target, buffer);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static unsigned char *hexparse(char *input) {
|
||||
if(strncmp(input, "0x", 2) != 0)
|
||||
return NULL;
|
||||
|
||||
size_t length = strlen(input);
|
||||
|
||||
unsigned char *target = calloc(sizeof(char), length);
|
||||
char *pos = input + 2;
|
||||
|
||||
for(size_t count = 0; count < length - 2; count++) {
|
||||
sscanf(pos, "%2hhx", &target[count]);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
static void secp256k1_erase(unsigned char *target, size_t length) {
|
||||
#if defined(__GNUC__)
|
||||
// memory barrier to avoid memset optimization
|
||||
memset(target, 0, length);
|
||||
__asm__ __volatile__("" : : "r"(target) : "memory");
|
||||
#else
|
||||
// if we can't, fill with random, still better than
|
||||
// risking avoid memset
|
||||
fill_random(target, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_erase_free(unsigned char *target, size_t length) {
|
||||
secp256k1_erase(target, length);
|
||||
free(target);
|
||||
}
|
||||
|
||||
secp256k1_t *secp256k1_new() {
|
||||
secp256k1_t *secp = malloc(sizeof(secp256k1_t));
|
||||
unsigned char randomize[32];
|
||||
|
||||
secp->kntxt = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
if(!fill_random(randomize, sizeof(randomize))) {
|
||||
printf("[-] failed to generate randomness\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// side-channel protection
|
||||
int val = secp256k1_context_randomize(secp->kntxt, randomize);
|
||||
assert(val);
|
||||
|
||||
// allocate keys and initialize them empty
|
||||
secp->seckey = calloc(sizeof(char), SECKEY_SIZE);
|
||||
secp->compressed = calloc(sizeof(char), COMPPUB_SIZE);
|
||||
secp->xcompressed = calloc(sizeof(char), XSERPUB_SIZE);
|
||||
|
||||
return secp;
|
||||
}
|
||||
|
||||
void secp256k1_free(secp256k1_t *secp) {
|
||||
secp256k1_context_destroy(secp->kntxt);
|
||||
secp256k1_erase_free(secp->seckey, SECKEY_SIZE);
|
||||
secp256k1_erase_free(secp->compressed, COMPPUB_SIZE);
|
||||
secp256k1_erase_free(secp->xcompressed, XSERPUB_SIZE);
|
||||
free(secp);
|
||||
}
|
||||
|
||||
static int secp256k1_populate_public_key(secp256k1_t *secp) {
|
||||
int retval;
|
||||
|
||||
retval = secp256k1_xonly_pubkey_from_pubkey(secp->kntxt, &secp->xpubkey, NULL, &secp->pubkey);
|
||||
assert(retval);
|
||||
|
||||
retval = secp256k1_xonly_pubkey_serialize(secp->kntxt, secp->xcompressed, &secp->xpubkey);
|
||||
assert(retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int secp256k1_populate_key(secp256k1_t *secp) {
|
||||
int retval;
|
||||
|
||||
retval = secp256k1_ec_pubkey_create(secp->kntxt, &secp->pubkey, secp->seckey);
|
||||
assert(retval);
|
||||
|
||||
size_t len = COMPPUB_SIZE;
|
||||
retval = secp256k1_ec_pubkey_serialize(secp->kntxt, secp->compressed, &len, &secp->pubkey, SECP256K1_EC_COMPRESSED);
|
||||
assert(retval);
|
||||
|
||||
// always compute the xonly pubkey as well, so we don't need to compute
|
||||
// it later for schnorr
|
||||
retval = secp256k1_keypair_create(secp->kntxt, &secp->keypair, secp->seckey);
|
||||
assert(retval);
|
||||
|
||||
return secp256k1_populate_public_key(secp);
|
||||
}
|
||||
|
||||
int secp256k1_generate_key(secp256k1_t *secp) {
|
||||
while(1) {
|
||||
if(!fill_random(secp->seckey, SECKEY_SIZE)) {
|
||||
printf("[-] failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(secp256k1_ec_seckey_verify(secp->kntxt, secp->seckey) == 0) {
|
||||
// try again
|
||||
continue;
|
||||
}
|
||||
|
||||
return secp256k1_populate_key(secp);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// backward compatibility
|
||||
int secp256k1_load_key(secp256k1_t *secp, char *key) {
|
||||
// only allow valid key size
|
||||
if(strlen(key) != (SECKEY_SIZE * 2) + 2)
|
||||
return 1;
|
||||
|
||||
unsigned char *binkey = hexparse(key);
|
||||
|
||||
free(secp->seckey);
|
||||
secp->seckey = binkey;
|
||||
|
||||
if(secp256k1_ec_seckey_verify(secp->kntxt, secp->seckey) == 0) {
|
||||
// invalid key
|
||||
return 1;
|
||||
}
|
||||
|
||||
return secp256k1_populate_key(secp);
|
||||
}
|
||||
|
||||
int secp256k1_load_private_key(secp256k1_t *secp, char *key) {
|
||||
return secp256k1_load_key(secp, key);
|
||||
}
|
||||
|
||||
int secp256k1_load_public_key(secp256k1_t *secp, char *key) {
|
||||
// only allow valid key size
|
||||
if(strlen(key) != (COMPPUB_SIZE * 2) + 2)
|
||||
return 1;
|
||||
|
||||
unsigned char *binkey = hexparse(key);
|
||||
|
||||
free(secp->compressed);
|
||||
secp->compressed = binkey;
|
||||
|
||||
if(!secp256k1_ec_pubkey_parse(secp->kntxt, &secp->pubkey, secp->compressed, COMPPUB_SIZE)) {
|
||||
printf("[-] failed to load public key\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return secp256k1_populate_public_key(secp);;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *secp265k1_shared_key(secp256k1_t *private, secp256k1_t *public) {
|
||||
unsigned char *shared = malloc(sizeof(unsigned char) * SHARED_SIZE);
|
||||
|
||||
int val = secp256k1_ecdh(private->kntxt, shared, &public->pubkey, private->seckey, NULL, NULL);
|
||||
assert(val);
|
||||
|
||||
return shared;
|
||||
}
|
||||
|
||||
unsigned char *secp256k1_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length) {
|
||||
secp256k1_sign_t signature;
|
||||
int retval;
|
||||
|
||||
if(length != SHA256_SIZE) {
|
||||
printf("[-] warning: you should only sign sha-256 hash, size mismatch\n");
|
||||
printf("[-] warning: you get warned\n");
|
||||
}
|
||||
|
||||
retval = secp256k1_ecdsa_sign(secp->kntxt, &signature.sig, hash, secp->seckey, NULL, NULL);
|
||||
assert(retval);
|
||||
|
||||
signature.serialized = malloc(sizeof(unsigned char) * SERSIG_SIZE);
|
||||
|
||||
retval = secp256k1_ecdsa_signature_serialize_compact(secp->kntxt, signature.serialized, &signature.sig);
|
||||
assert(retval);
|
||||
|
||||
return signature.serialized;
|
||||
}
|
||||
|
||||
secp256k1_sign_t *secp256k1_load_signature(secp256k1_t *secp, unsigned char *serialized, size_t length) {
|
||||
secp256k1_sign_t *signature;
|
||||
|
||||
if(length != SERSIG_SIZE) {
|
||||
printf("[-] serialized signature length mismatch, expected %u bytes\n", SERSIG_SIZE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
signature = calloc(sizeof(secp256k1_sign_t), 1);
|
||||
|
||||
signature->length = length;
|
||||
signature->serialized = malloc(length);
|
||||
memcpy(signature->serialized, serialized, length);
|
||||
|
||||
if(!secp256k1_ecdsa_signature_parse_compact(secp->kntxt, &signature->sig, signature->serialized)) {
|
||||
printf("[-] failed to parse the signature\n");
|
||||
// FIXME: cleanup
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
void secp256k1_sign_free(secp256k1_sign_t *signature) {
|
||||
secp256k1_erase_free(signature->serialized, signature->length);
|
||||
free(signature);
|
||||
}
|
||||
|
||||
int secp256k1_sign_verify(secp256k1_t *secp, secp256k1_sign_t *signature, unsigned char *hash, size_t length) {
|
||||
if(length != SHA256_SIZE) {
|
||||
printf("[-] warning: you should only check sha-256 hash, size mismatch\n");
|
||||
}
|
||||
|
||||
return secp256k1_ecdsa_verify(secp->kntxt, &signature->sig, hash, &secp->pubkey);
|
||||
}
|
||||
|
||||
unsigned char *secp256k1_schnorr_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length) {
|
||||
unsigned char aux[32];
|
||||
unsigned char *signature;
|
||||
int retval;
|
||||
|
||||
if(length != SHA256_SIZE) {
|
||||
printf("[-] warning: you should only sign sha-256 hash, size mismatch\n");
|
||||
printf("[-] warning: you get warned\n");
|
||||
}
|
||||
|
||||
if(!fill_random(aux, sizeof(aux))) {
|
||||
printf("[-] failed to generate randomness\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
signature = malloc(sizeof(unsigned char) * SCHSIG_SIZE);
|
||||
|
||||
retval = secp256k1_schnorrsig_sign32(secp->kntxt, signature, hash, &secp->keypair, aux);
|
||||
assert(retval);
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
int secp256k1_schnorr_verify(secp256k1_t *secp, unsigned char *signature, size_t siglen, unsigned char *hash, size_t hashlen) {
|
||||
if(hashlen != SHA256_SIZE) {
|
||||
printf("[-] warning: you should only check sha-256 hash, size mismatch\n");
|
||||
}
|
||||
|
||||
if(siglen != SCHSIG_SIZE) {
|
||||
printf("[-] invalid signature length, should be %u bytes\n", SCHSIG_SIZE);
|
||||
return 2;
|
||||
}
|
||||
|
||||
return secp256k1_schnorrsig_verify(secp->kntxt, signature, hash, hashlen, &secp->xpubkey);
|
||||
}
|
||||
|
||||
void secp256k1_dumps(secp256k1_t *secp) {
|
||||
printf("Private Key: ");
|
||||
dumphex(secp->seckey, SECKEY_SIZE);
|
||||
|
||||
printf("Public Key : ");
|
||||
dumphex(secp->compressed, COMPPUB_SIZE);
|
||||
|
||||
printf("X-Only Key : ");
|
||||
dumphex(secp->xcompressed, XSERPUB_SIZE);
|
||||
}
|
||||
|
||||
// backward compatibility
|
||||
char *secp256k1_export(secp256k1_t *secp) {
|
||||
return hexifier(secp->seckey, SECKEY_SIZE);
|
||||
}
|
||||
|
||||
// return private key in hex format
|
||||
char *secp256k1_private_key(secp256k1_t *secp) {
|
||||
return secp256k1_export(secp);
|
||||
}
|
||||
|
||||
char *secp256k1_public_key(secp256k1_t *secp) {
|
||||
return hexifier(secp->compressed, COMPPUB_SIZE);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_SECP_MAIN
|
||||
int main() {
|
||||
secp256k1_t *wendy = secp256k1_new();
|
||||
secp256k1_generate_key(wendy);
|
||||
|
||||
printf("Wendy:\n");
|
||||
dumphex(wendy->seckey, SECKEY_SIZE);
|
||||
dumphex(wendy->compressed, COMPPUB_SIZE);
|
||||
dumphex(wendy->xcompressed, XSERPUB_SIZE);
|
||||
|
||||
// bob
|
||||
secp256k1_t *bob = secp256k1_new();
|
||||
secp256k1_load_key(bob, "0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83");
|
||||
|
||||
printf("\n");
|
||||
printf("Bob:\n");
|
||||
dumphex(bob->seckey, SECKEY_SIZE);
|
||||
dumphex(bob->compressed, COMPPUB_SIZE);
|
||||
dumphex(bob->xcompressed, XSERPUB_SIZE);
|
||||
|
||||
// export functions
|
||||
char *priv = secp256k1_private_key(bob);
|
||||
char *pubk = secp256k1_public_key(bob);
|
||||
printf("Private export: %s\n", priv);
|
||||
printf("Public export: %s\n", pubk);
|
||||
free(priv);
|
||||
|
||||
secp256k1_t *bobpub = secp256k1_new();
|
||||
int val = secp256k1_load_public_key(bobpub, "0x03310ec949bd4f7fc24f823add1394c78e1e9d70949ccacf094c027faa20d99e21");
|
||||
printf("Public key loader: %d\n", val);
|
||||
secp256k1_dumps(bobpub);
|
||||
|
||||
// alice
|
||||
secp256k1_t *alice = secp256k1_new();
|
||||
secp256k1_load_key(alice, "0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec");
|
||||
|
||||
printf("\n");
|
||||
printf("Alice:\n");
|
||||
dumphex(alice->seckey, SECKEY_SIZE);
|
||||
dumphex(alice->compressed, COMPPUB_SIZE);
|
||||
dumphex(alice->xcompressed, XSERPUB_SIZE);
|
||||
|
||||
unsigned char *shared1 = secp265k1_shared_key(bob, alice);
|
||||
unsigned char *shared2 = secp265k1_shared_key(alice, bob);
|
||||
|
||||
printf("\n");
|
||||
printf("Shared Key:\n");
|
||||
dumphex(shared1, SHARED_SIZE);
|
||||
dumphex(shared2, SHARED_SIZE);
|
||||
|
||||
secp256k1_erase_free(shared1, SHARED_SIZE);
|
||||
secp256k1_erase_free(shared2, SHARED_SIZE);
|
||||
|
||||
// Hello, world!
|
||||
unsigned char hash[32] = {
|
||||
0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
|
||||
0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
|
||||
0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
|
||||
0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
|
||||
};
|
||||
|
||||
unsigned char *sign = secp256k1_sign_hash(bob, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature (ecdsa):\n");
|
||||
dumphex(sign, SERSIG_SIZE);
|
||||
|
||||
secp256k1_sign_t *sigobj = secp256k1_load_signature(bob, sign, SERSIG_SIZE);
|
||||
int valid = secp256k1_sign_verify(bob, sigobj, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature valid: %d\n", valid);
|
||||
|
||||
secp256k1_sign_free(sigobj);
|
||||
|
||||
// using bobpub
|
||||
sigobj = secp256k1_load_signature(bobpub, sign, SERSIG_SIZE);
|
||||
valid = secp256k1_sign_verify(bobpub, sigobj, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature valid (using bob public key only): %d\n", valid);
|
||||
|
||||
secp256k1_erase_free(sign, SERSIG_SIZE);
|
||||
secp256k1_sign_free(sigobj);
|
||||
|
||||
sign = secp256k1_schnorr_sign_hash(bob, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature (schnorr):\n");
|
||||
dumphex(sign, SCHSIG_SIZE);
|
||||
|
||||
valid = secp256k1_schnorr_verify(bob, sign, SCHSIG_SIZE, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature valid: %d\n", valid);
|
||||
|
||||
valid = secp256k1_schnorr_verify(bobpub, sign, SCHSIG_SIZE, hash, sizeof(hash));
|
||||
|
||||
printf("\n");
|
||||
printf("Signature valid (using bob pubkey key only): %d\n", valid);
|
||||
|
||||
secp256k1_erase_free(sign, SCHSIG_SIZE);
|
||||
|
||||
printf("\n");
|
||||
printf("Wendy Export:\n");
|
||||
char *export = secp256k1_export(wendy);
|
||||
printf(">> %s\n", export);
|
||||
free(export);
|
||||
|
||||
printf("\n");
|
||||
printf("Wendy Keys dump:\n");
|
||||
secp256k1_dumps(wendy);
|
||||
|
||||
secp256k1_free(bob);
|
||||
secp256k1_free(alice);
|
||||
secp256k1_free(wendy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef SECP256K1_V_MOD
|
||||
#define SECP256K1_V_MOD
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
typedef struct secp256k1_t {
|
||||
secp256k1_context *kntxt; // library context
|
||||
unsigned char *seckey; // ec private key
|
||||
|
||||
unsigned char *compressed; // ec public key serialized
|
||||
secp256k1_pubkey pubkey; // ec public key
|
||||
|
||||
unsigned char *xcompressed; // x-only serialized key
|
||||
secp256k1_xonly_pubkey xpubkey; // x-only public key
|
||||
secp256k1_keypair keypair; // keypair opaque representation
|
||||
// needed for schnorr
|
||||
|
||||
} secp256k1_t;
|
||||
|
||||
typedef struct secp256k1_sign_t {
|
||||
secp256k1_ecdsa_signature sig;
|
||||
unsigned char *serialized;
|
||||
size_t length;
|
||||
|
||||
} secp256k1_sign_t;
|
||||
|
||||
#define SECKEY_SIZE 32 // secret key size
|
||||
#define SHARED_SIZE 32 // ecdh shared key size
|
||||
#define COMPPUB_SIZE 33 // compressed public key size
|
||||
#define XSERPUB_SIZE 32 // x-only public key serialized size
|
||||
#define SERSIG_SIZE 64 // serialized signature size
|
||||
#define SCHSIG_SIZE 64 // internal schnorr signature size
|
||||
|
||||
#define SHA256_SIZE 32 // sha-256 digest length
|
||||
|
||||
secp256k1_t *secp256k1_new();
|
||||
void secp256k1_free(secp256k1_t *secp);
|
||||
|
||||
int secp256k1_generate_key(secp256k1_t *secp);
|
||||
unsigned char *secp265k1_shared_key(secp256k1_t *private, secp256k1_t *public);
|
||||
unsigned char *secp256k1_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length);
|
||||
|
||||
secp256k1_sign_t *secp256k1_load_signature(secp256k1_t *secp, unsigned char *serialized, size_t length);
|
||||
int secp256k1_sign_verify(secp256k1_t *secp, secp256k1_sign_t *signature, unsigned char *hash, size_t length);
|
||||
unsigned char *secp256k1_schnorr_sign_hash(secp256k1_t *secp, unsigned char *hash, size_t length);
|
||||
int secp256k1_schnorr_verify(secp256k1_t *secp, unsigned char *signature, size_t siglen, unsigned char *hash, size_t hashlen);
|
||||
void secp256k1_sign_free(secp256k1_sign_t *signature);
|
||||
|
||||
char *secp256k1_export(secp256k1_t *secp);
|
||||
char *secp256k1_private_key(secp256k1_t *secp);
|
||||
char *secp256k1_public_key(secp256k1_t *secp);
|
||||
void secp256k1_dumps(secp256k1_t *secp);
|
||||
int secp256k1_load_key(secp256k1_t *secp, char *key);
|
||||
|
||||
int secp256k1_load_private_key(secp256k1_t *secp, char *key);
|
||||
int secp256k1_load_public_key(secp256k1_t *secp, char *key);
|
||||
#endif
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
module secp256k1
|
||||
|
||||
import encoding.hex
|
||||
import crypto.sha256
|
||||
import freeflowuniverse.herolib.crypt.secp256k1
|
||||
|
||||
fn test_check() {
|
||||
println('${'[+] initializing libsecp256 vlang wrapper'}')
|
||||
|
||||
wendy := secp256k1.new()!
|
||||
webdy_priv_key := wendy.private_key_hex()
|
||||
webdy_pub_key := wendy.public_key_hex()
|
||||
println('-------')
|
||||
println('Wendy Private: ${webdy_priv_key}')
|
||||
println('Wendy Public: ${webdy_pub_key}')
|
||||
println('-------')
|
||||
|
||||
// create 'bob' from a private key, full features will be available
|
||||
bob := secp256k1.new(
|
||||
privhex: '0x478b45390befc3097e3e6e1a74d78a34a113f4b9ab17deb87e9b48f43893af83'
|
||||
)!
|
||||
|
||||
// create 'alice' from a private key, full features will be available
|
||||
alice := secp256k1.new(
|
||||
privhex: '0x8225825815f42e1c24a2e98714d99fee1a20b5ac864fbcb7a103cd0f37f0ffec'
|
||||
)!
|
||||
|
||||
// create 'bobpub' from bob only public key, reduced features available (only sign check, shared keys, etc.)
|
||||
bobpub := secp256k1.new(
|
||||
pubhex: bob.public_key_hex()
|
||||
)!
|
||||
|
||||
// create 'alicepub' from alice only public key, reduced features available
|
||||
alicepub := secp256k1.new(
|
||||
pubhex: alice.public_key_hex()
|
||||
)!
|
||||
|
||||
shr1 := bob.sharedkeys(alice)
|
||||
println('${shr1}')
|
||||
|
||||
shr2 := alice.sharedkeys(bob)
|
||||
println('${shr2}')
|
||||
|
||||
// example in real world, where private key is available and only target public key
|
||||
shr1pub := bob.sharedkeys(alicepub)
|
||||
println('${shr1pub}')
|
||||
|
||||
shr2pub := alice.sharedkeys(bobpub)
|
||||
println('${shr2pub}')
|
||||
|
||||
println('-----')
|
||||
|
||||
mut message := 'Hello world, this is my awesome message'
|
||||
message += message
|
||||
message += message
|
||||
message += message
|
||||
message += message
|
||||
|
||||
h256 := sha256.hexhash(message)
|
||||
println('${h256}')
|
||||
println('${h256.len}')
|
||||
println('${sha256.sum(message.bytes())}')
|
||||
|
||||
parsed := hex.decode(h256) or { panic(err) }
|
||||
println('${parsed}')
|
||||
println('${parsed.len}')
|
||||
|
||||
//
|
||||
// signature (ecdca)
|
||||
//
|
||||
signed := alice.sign_data(message.bytes())
|
||||
println('${signed}')
|
||||
|
||||
signed_hex := alice.sign_data_hex(message.bytes())
|
||||
println('${signed_hex}')
|
||||
println('${signed_hex.len}')
|
||||
|
||||
signed_str := alice.sign_str(message)
|
||||
println('${signed_str}')
|
||||
println('${signed_str.len}')
|
||||
|
||||
signed_str_hex := alice.sign_str_hex(message)
|
||||
assert signed_str_hex == '656699dde22d8b89d91070dee4fc8dba136172fb54e6de475024c40e4f8d5111562212c8976b5a4ccd530bdb7f40c5d9bd2cdeeec1473656566fbb9c4576ed8c'
|
||||
assert signed_str_hex.len == 128
|
||||
|
||||
// instanciate alice with only her public key
|
||||
assert alicepub.verify_data(signed, message.bytes()) == true
|
||||
assert alicepub.verify_str_hex(signed_str_hex, message) == true
|
||||
assert alicepub.verify_str_hex(signed_str_hex, message + 's') == false
|
||||
|
||||
//
|
||||
// signature (schnorr)
|
||||
//
|
||||
// schnorr_signed := alice.schnorr_sign_data(message.bytes())
|
||||
// println('${schnorr_signed}')
|
||||
|
||||
// schnorr_signed_hex := alice.schnorr_sign_data_hex(message.bytes())
|
||||
// println('${schnorr_signed_hex}')
|
||||
|
||||
// schnorr_signed_str := alice.schnorr_sign_str(message)
|
||||
// println('${schnorr_signed_str}')
|
||||
|
||||
// schnorr_signed_str_hex := alice.schnorr_sign_str_hex(message)
|
||||
// println('${schnorr_signed_str_hex}')
|
||||
|
||||
// println('${alicepub.schnorr_verify_data(schnorr_signed, message.bytes())}')
|
||||
// println('${alicepub.schnorr_verify_str(schnorr_signed_str, message)}')
|
||||
|
||||
// // should fails, it's not the right signature method (ecdsa / schnorr)
|
||||
// println('${alicepub.verify_data(schnorr_signed, message.bytes())}')
|
||||
// println('${alicepub.verify_str(schnorr_signed_str, message)}')
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
Module {
|
||||
name: 'secp256k1'
|
||||
description: 'secp256k1 in v'
|
||||
version: '0.2.0'
|
||||
license: 'MIT'
|
||||
dependencies: []
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
module core
|
||||
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.data.dbfs
|
||||
import freeflowuniverse.herolib.core.redisclient
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
fn donedb() !&dbfs.DB {
|
||||
fn donedb() !&redisclient.Redis {
|
||||
mut context := base.context()!
|
||||
mut collection := context.dbcollection()!
|
||||
mut db := collection.db_get_create(name: 'todo', withkeys: true)!
|
||||
return &db
|
||||
return context.redis()!
|
||||
}
|
||||
|
||||
pub fn done_set(key string, val string) ! {
|
||||
mut db := donedb()!
|
||||
db.set(key: key, value: val)!
|
||||
db.hset("context:done",key, val)!
|
||||
}
|
||||
|
||||
pub fn done_get(key string) ?string {
|
||||
mut db := donedb() or { panic(err) }
|
||||
return db.get(key: key) or { return none }
|
||||
return db.hget("context:done", key) or { return none }
|
||||
}
|
||||
|
||||
pub fn done_delete(key string) ! {
|
||||
mut db := donedb()!
|
||||
db.delete(key: key)!
|
||||
db.hdel("context:done", key)!
|
||||
}
|
||||
|
||||
pub fn done_get_str(key string) string {
|
||||
@@ -38,7 +36,7 @@ pub fn done_get_int(key string) int {
|
||||
|
||||
pub fn done_exists(key string) bool {
|
||||
mut db := donedb() or { panic(err) }
|
||||
return db.exists(key: key) or { false }
|
||||
return db.hexists("context:done", key) or { false }
|
||||
}
|
||||
|
||||
pub fn done_print() ! {
|
||||
@@ -54,5 +52,5 @@ pub fn done_print() ! {
|
||||
|
||||
pub fn done_reset() ! {
|
||||
mut db := donedb()!
|
||||
db.destroy()!
|
||||
db.del("context:done")!
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user