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
inputUint8Array any number of bytes
Returns Uint8Array 256 bit (32 byte) hash
Verify ed25519 signature
messageUint8Array any number of bytes (TODO: test!)sigUint8Array 64 byte ed25519 signature over messagepublicKeyUint8Array 32 byte ed25519 public key
Returns boolean indicates whether the signature is valid
Keccak 256 bit cryptographic hash function (aka SHA-3)
inputUint8Array any number of bytes
Returns Uint8Array 256 bit (32 byte) hash
SHA-2 256 bit cryptographic hash function
inputUint8Array 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
hexHexStr<T>
Returns Bytes
Encode bytes as hex string
bytesT
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.
msgoptsopts.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.
targetURL : URI where channel is registered.deployerUint8ArraypayForPayFor<IDeployData>optsProxyOptsopts.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.
$0any$0.target$0.method$0.args
timestampnumberdeployerUint8ArraypayForPayFor<IDeployData>optsSendOptsopts.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
grpcGRPCAccess 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
-
deployDataIDeployData a DeployData (cf CasperMessage.proto)deployData.deployerpublic keydeployData.termA string of rholang code (for example @"world"!("Hello!") )deployData.timestampmillisecond timestamp e.g. new Date().valueOf()deployData.sigsignature of (hash(term) + timestamp) using private keydeployData.sigAlgorithmname of the algorithm used to signdeployData.phloLimitdeployData.phloPricedeployData.validAfterBlockNumber???ISSUE???
-
autoCreateBlockboolean 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.
-
parIPar : JSON-ish Par data. See protobuf/RhoTypes.proto -
depthnumber (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.
dObjectd.userUint8Array public key as indeployerindoDeployd.timestampnumber timestamp (ms) as in doDeploy
nameQtynumber 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
-
blockHashstring : 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
-
blockDepthnumber : 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.
dataany : 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
-
parIPar : 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
termObjIPar
Returns Uint8Array
Converts an RHOCore object back to JavaScript data
parIPar A RHOCore representation of a Rholang term
Returns JsonExt<(URL | GPrivate)> JSON-serializable data
Converts an RHOCore object into Rholang source form
parIPar 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.
idUint8Array
-
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.
seedPrivateKey 32 bytes, as from crypto.randombytes(32)
ISSUE: if the caller wants the bytes, we go bytes -> hex -> bytes
Returns HexStr<PublicKey>
bytesUint8Array
Returns Signature
bsUint8Array
Returns HexStr<Signature>
textstring
Returns Signature
textstring
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
pkUint8Array ed25519 public key
Returns IRevAddress
Parse REV Address
-
addressstring -
Throws any Error on ill-formed address
Returns IRevAddress
a port of casper/SignDeployment.scala
ISSUE: only ed25519 is supported.
keyKeyPairdeployDataDeployData
Returns DeployData
deployDataDeployData
Returns boolean