Cryptographic functions from Rholang
refs:
- RChain Cryptography Specification May 2018
- rholang/examples/tut-hash-functions.rho Aug 2018
- rholang/examples/tut-verify-channel.md Aug 2018
See also RHOCore.wrapHash
// Suppose we have Nathan Hale's public key:
const { RholangCrypto, Hex } = require('rchain-api');
const halePub = Hex.decode(
'd759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48');
// And we are presented with a document that he purportedly signed:
const doc = 'I regret that I have but one life to live for my country.';
const sig1 = Hex.decode(
'af42db4ae7a23ee182f7aabc3a73fa89834bc0daefab94d0f3e28c508557c3d3' +
'f06c67c28ebd2768ffa0b320330ec5089a9ae7519534fe70e9d06145d8caf40c');
// Signatures are conventionally computed over a document's hash.
// In this case, we happen to know it's a Blake2b 256 bit hash:
const digest = RholangCrypto.blake2b256Hash(Buffer.from(doc));
// Indeed, the signature is valid.
assert(RholangCrypto.ed25519Verify(digest, sig1, halePub));
// If the signature is altered even slightly, validation fails:
const sig2 = sig1;
sig2[0] = 123;
assert(!RholangCrypto.ed25519Verify(digest, sig2, halePub));
Blake2b 256 bit cryptographic hash function
input
Uint8Array any number of bytes
Returns Uint8Array 256 bit (32 byte) hash
Verify ed25519 signature
message
Uint8Array any number of bytes (TODO: test!)sig
Uint8Array 64 byte ed25519 signature over messagepublicKey
Uint8Array 32 byte ed25519 public key
Returns boolean indicates whether the signature is valid
Keccak 256 bit cryptographic hash function (aka SHA-3)
input
Uint8Array any number of bytes
Returns Uint8Array 256 bit (32 byte) hash
SHA-2 256 bit cryptographic hash function
input
Uint8Array any number of bytes
Returns Uint8Array 256 bit (32 byte) hash
Hex (base16) encoding and decoding
A byte sequence
Type: (Uint8Array | Buffer)
Decode hex string to bytes
hex
HexStr<T>
Returns Bytes
Encode bytes as hex string
bytes
T
Returns string
Hex (base16) encoding of a Bytes type
Type: string
Proxy method calls to registered RChain channels.
Make a rholang term for looking up a target and calling a method.
msg
opts
opts.unary
: For better compositionality, JS args are combined into one list arg on the rholang side.
Make an object that proxies method calls to registered RChain channels.
For rholang calling conventions, see callSource
.
target
URL : URI where channel is registered.deployer
Uint8ArraypayFor
PayFor<IDeployData>opts
ProxyOptsopts.rnode
: access to RChain node via gRPCopts.clock
: access to millisecond-resolution clock.opts.delay
: an optional async function to call between sending a call and listening for the response.opts.unary
: whether to use unary calling conventions.opts.predeclare
: names to pre-declare afterreturn
deployData
: as in doDeploy (though term is ignored and replaced)
Returns Receiver
Call a method on a registered RChain channel.
For rholang calling conventions, see callSource
.
$0
any$0.target
$0.method
$0.args
timestamp
numberdeployer
Uint8ArraypayFor
PayFor<IDeployData>opts
SendOptsopts.rnode
: access to RChain node via gRPCopts.delay
: an optional async function to call between sending a call and listening for the response.opts.unary
: whether to use unary calling conventions.
target
: URI where channel is registered.deployData
: as in doDeploy (though term is ignored and replaced)
RChain node API client
Methods are asynchronous; they return promises. Where CasperMessage.proto specifies an Either, this API resolves the promise on success or rejects it on failure.
The promise may also reject for the usual gRPC reasons such as
UNAVAILABLE: Connect Failed
.
Refs:
- Node API Specification May 2018
- CasperMessage.proto v0.9.1 bf1b2c6 Mar 28, 2019 and dependencies such as
- RChain Protocol Documentation
grpc
GRPCAccess access make gRPC network callsendPoint
{host: string, port: number} rnode gRPC service
// Get current block info
const { RNode, REV, Ed25519keyPair, Hex } = require('rchain-api');
const grpc = require('grpc');
const rnode = RNode(grpc, { host: 'localhost', port: 40401 });
rnode.showBlocks().then((blocks) => { assert.ok(blocks[0].blockHash); });
// Deploy a simple Rholang process, given a key to authorize payment.
const term = '@"world"!("Hello!")';
const myKey = Ed25519keyPair(Hex.decode('11'.repeat(32)));
const timestamp = new Date('2019-04-12T17:59:29.274Z').valueOf();
const info = REV.SignDeployment.sign(myKey, { timestamp, term, phloLimit: 10000, phloPrice: 1 });
rnode.doDeploy(info, true).then((message) => { assert(message.startsWith('Success')); });
Returns IRNode a thin wrapper around a gRPC client stub
Creates a block on your node
Returns Promise<string> A promise for response message
Deploys a rholang term to a node
-
deployData
IDeployData a DeployData (cf CasperMessage.proto)deployData.deployer
public keydeployData.term
A string of rholang code (for example @"world"!("Hello!") )deployData.timestamp
millisecond timestamp e.g. new Date().valueOf()deployData.sig
signature of (hash(term) + timestamp) using private keydeployData.sigAlgorithm
name of the algorithm used to signdeployData.phloLimit
deployData.phloPrice
deployData.validAfterBlockNumber
???ISSUE???
-
autoCreateBlock
boolean automatically create a new block after deploy transaction success -
Throws Error Could not deploy, casper instance was not available yet.
-
Throws Error Missing / invalid / wrong size signature
Returns Promise<string> A promise for message
Listen for a continuation at an individual name or JOINed set of names in the tuplespace
Returns Promise<ListeningNameContinuationResponse> promise for DataWithBlockInfo
Listen for data at a name in the RChain tuple-space.
-
par
IPar : JSON-ish Par data. See protobuf/RhoTypes.proto -
depth
number (optional, default1
) -
blockDepth
: Number of blocks to look back in for the name to listen on -
Throws any Error if status is not Success
Returns Promise<Array<DataWithBlockInfo>> : promise for DataWithBlockInfo[]
Ask rnode to compute ids of top level private names, given deploy parameters.
d
Objectd.user
Uint8Array public key as indeployer
indoDeploy
d.timestamp
number timestamp (ms) as in doDeploy
nameQty
number how many names to preview? (max: 1024)
Returns Promise<Array<Buffer>> a byte Buffer for each id
Retrieve a block with the tuplespace for a specific block hash
-
blockHash
string : String of the hash for the block being requested -
Throws any Error if the hash is blank or does not correspond to an existing block
Returns any BlockInfo structure that will include all metadata and also includes Tuplespace
Retrieve the block summary for a series of blocks starting with the most recent, including the number of blocks specified by the block_depth
-
blockDepth
number : Number indicating the number of blocks to retrieve -
Throws any Error if blockDepth < 1 or no blocks were able to be retrieved
Returns Promise<BlockInfoWithoutTuplespace> List of BlockInfoWithoutTuplespace structures for each block retrieved
Exchanging data between Rholang and JavaScript
RChain uses gRPC and protobuf for its network
protocol. RhoTypes.proto gives the protobuf messages for
Rholang. The main one is Par
.
The RHOCore mapping here is derived from Currin et. al but uses a differet mapping for object properties and includes more ground rholang types.
ISSUE: Document support for unforgeable names.
Refs:
- Mobile process calculi for programming the blockchain Currin, Denman, Eykholt, Meredith Dec 2016
- RhoTypes.proto v0.9.1 bf1b2c6 Mar 28, 2019
JSON to rholang and back
const { RHOCore, RhoTypes } = require('rchain-api');
const data = [true, 1, 'abc', null, [1, 2, 3]];
const rhoProto = RHOCore.fromJSData(data);
RhoTypes.Par.verify(rhoProto);
assert.deepEqual(RHOCore.toJSData(rhoProto), data);
assert.equal(RHOCore.toRholang(rhoProto),
'[true, 1, "abc", Nil, [1, 2, 3]]');
Uri and ByteArray
const { URL } = require('url');
const { RHOCore, Hex } = require('rchain-api');
const data = [new URL('rho:id:123'), Hex.decode('deadbeef')];
const rhoProto = RHOCore.fromJSData(data);
assert.deepEqual(RHOCore.toJSData(rhoProto), data);
assert.equal(RHOCore.toRholang(rhoProto),
'[`rho:id:123`, "deadbeef".hexToBytes()]');
Turn unforgeable names from raw bytes to protobuf Par shape
Build Rholang expression from Javascript data.
This is the inverse of toJSData
.
data
any : number, string, array, etc.; see toJSData for details.
Returns any : A rholang term in Protobuf's JSON representation,
i.e. IPar
derived from RhoTypes.proto.
Convert the ack channel into a HEX-formatted unforgeable name
-
par
IPar : JSON-ish Par data: https://github.com/rchain/rchain/blob/master/models/src/main/protobuf/RhoTypes.proto -
Throws any Error if the Par does not represent an unforgeable name
Returns string HEX-formatted string of unforgeable name's Id
Template tag for RHOCore interpolation
Turns a rholang term into a byte-array compatible with Rholang
termObj
IPar
Returns Uint8Array
Converts an RHOCore object back to JavaScript data
par
IPar A RHOCore representation of a Rholang term
Returns JsonExt<(URL | GPrivate)> JSON-serializable data
Converts an RHOCore object into Rholang source form
par
IPar A RHOCore representation of a Rholang term
Returns string A rholang stringISSUE: Use intersection types to constrain par param further than IPar?
Get printable form of unforgeable name, given id.
id
Uint8Array
-
jsData
: JS Data compatible with Rholang, used to compute the hash -
Throws any Error if the js_data contains a non-Rholang data structure
Returns any HEX-formatted string representing the computed hash
Build key pair from seed.
seed
PrivateKey 32 bytes, as from crypto.randombytes(32)
ISSUE: if the caller wants the bytes, we go bytes -> hex -> bytes
Returns HexStr<PublicKey>
bytes
Uint8Array
Returns Signature
bs
Uint8Array
Returns HexStr<Signature>
text
string
Returns Signature
text
string
Returns HexStr<Signature>
REV transaction, vault support
Refs:
- REV Vault Feb 2019
// Suppose Alice generates a key pair.
const { REV, Ed25519keyPair, Hex } = require('rchain-api');
const aliceKey = Ed25519keyPair(Hex.decode('11'.repeat(32)));
const alicePub = aliceKey.publicKey();
assert.equal(alicePub, 'd04ab232742bb4ab3a1368bd4615e4e6d0224ab71a016baf8520a332c9778737');
// She can then share her REV address.
const aliceAddr = REV.RevAddress.fromPublicKey(Hex.decode(alicePub));
assert.equal(aliceAddr.toString(), '11112cFcjtrjwn7qCDvTLMu5jEvMSBN2qT1sBwQxDP9AyQCVi26xKZ');
// She can also sign deployments:
const term = '@"world"!("Hello!")';
const timestamp = new Date('2019-04-12T17:59:29.274Z').valueOf();
const info = REV.SignDeployment.sign(aliceKey, { timestamp, term });
assert.deepEqual(info.deployer, Hex.decode(alicePub));
assert.equal(Hex.encode(info.sig).slice(0, 16), 'ebc47a0a923b7feb');
assert(REV.SignDeployment.verify(info));
// We can check a REV address before deploying any code.
assert.throws(() => {
REV.RevAddress.parse('123');
});
A RevAddress refers to a REV vault.
Use toString()
to get base58 form.
Refs:
Compute REV Address from public key
pk
Uint8Array ed25519 public key
Returns IRevAddress
Parse REV Address
-
address
string -
Throws any Error on ill-formed address
Returns IRevAddress
a port of casper/SignDeployment.scala
ISSUE: only ed25519 is supported.
key
KeyPairdeployData
DeployData
Returns DeployData
deployData
DeployData
Returns boolean